A Property Kind Calculus for Measurement Metrology

19.4. The method ladder: GUM ⊂ Willink ⊂ SSPRC🔗

For a model Y = f(X_1,\dots,X_k) with mutually independent, uncertain inputs, three methods estimate the uncertainty of Y, in increasing fidelity and cost. They are one pipeline — extract each input's contribution, combine the independent contributions, summarize — differing only in what a contribution is:

  • GUM / law of propagation. Linearize and combine variances only: u_c(Y) = \sqrt{\textstyle\sum_i c_i^2\, u^2(X_i)}, \qquad c_i = \partial f/\partial X_i. A symmetric, Gaussian answer.

  • Willink's cumulants method  (Willink, 2005)Marginal noteRobin Willink (2005). “A procedure for the evaluation of measurement uncertainty based on moments”. Metrologia. 42(5).. The same linearization, but combine the second and fourth cumulants, u_Y^2 = \sum_i c_i^2 u_i^2 and w_Y = \sum_i c_i^4 w_i, form the excess \gamma_Y = w_Y/u_Y^4, and read an expanded-uncertainty half-width off the Pearson family via the coverage-factor k_p(\gamma_Y). This recovers the tail shape (kurtosis) GUM discards.

  • The SSPRC method  (Degenhardt et al., 2025)Marginal noteJohannes Degenhardt, Rainer Tutsch, Xiukun Hu, and Gaoliang Dai (2025). “A practically oriented, efficient alternative to the Monte Carlo method for measurement uncertainty estimation”. Metrologia. 62(2).. No linearization: systematically sample each input, propagate each separately through the model, reconstruct each input's deviation distribution, and combine them by convolution. It captures full non-linearity and each input's individual uncertainty contribution, at a fraction of the model evaluations a random Monte Carlo needs.

The organizing fact is that these are provably nested. All three rest on the additivity of cumulants under independent summation — Willink's \kappa_r\!\bigl(\sum_j a_j Z_j\bigr) = \sum_j a_j^{\,r}\,\kappa_r(Z_j). GUM keeps only \kappa_2; Willink keeps \kappa_2 and \kappa_4; SSPRC's convolution combines all cumulants numerically (Willink himself calls his method "convolution of the components in the linearized formulation"). So the ladder is a chain of homomorphisms between the methods' contribution types, and each coarser rung is a projection of the finer one — the claim the ladder theorems below discharge, all five now proved over ℝ: T1 and T2 relate GUM and Willink; T5 shows convolution adds cumulants; T3 uses it to identify Willink with the (\kappa_2,\kappa_4) truncation of the linearized SSPRC; and T4 pins the SSPRC reference to the mean for an affine model. The sensitivity coefficients c_i the two linearized rungs need come from the autograd bridge below, not by hand.

Definition19.4.1
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 1✓L∃∀N

The GUM combined standard uncertainty \sqrt{\sum_i c_i^2 u_i^2}, over a list of sensitivity / moment-data pairs. The coarsest rung.

Lean code for Definition19.4.1●1 definition
  • defdefined in PropertyKindCalculus/Uncertainty/Combine.lean
    complete
    def PropertyKindCalculus.Uncertainty.gumStdUnc
      (terms :
        List (Float × PropertyKindCalculus.Uncertainty.MomentData Float)) :
      Float
    def PropertyKindCalculus.Uncertainty.gumStdUnc
      (terms :
        List
          (Float ×
            PropertyKindCalculus.Uncertainty.MomentData
              Float)) :
      Float
    **GUM / law-of-propagation combined standard uncertainty:** `√(Σ cᵢ² uᵢ²)`. 
Proof for Definition 19.4.1
uses 0

Realized. gumStdUnc folds the \kappa_2 contributions. Stage 0 supplied the c_i explicitly; Stage 1 now sources them from the autograd carrier (one reverse pass over the write-once model at the input means), leaving this fold unchanged — the Degenhardt example checks the two agree, both giving u_c = 1.662.

Lean code for Definition19.4.2●1 definition
  • defdefined in PropertyKindCalculus/Uncertainty/Combine.lean
    complete
    def PropertyKindCalculus.Uncertainty.willinkCombine
      (terms :
        List (Float × PropertyKindCalculus.Uncertainty.MomentData Float)) :
      Float × Float
    def PropertyKindCalculus.Uncertainty.willinkCombine
      (terms :
        List
          (Float ×
            PropertyKindCalculus.Uncertainty.MomentData
              Float)) :
      Float × Float
    **Willink cumulant combine** → `(u_Y, γ_Y)`: the combined standard uncertainty and the
    coefficient of excess (kurtosis) `γ_Y = w_Y / u_Y⁴`, with `u_Y² = Σ cᵢ² uᵢ²` and
    `w_Y = Σ cᵢ⁴ wᵢ`. 
Definition19.4.3
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 0✓L∃∀N

The Monte Carlo reference propagator: sample the joint input distribution, push each draw through the model, report the sample mean and standard uncertainty of the output. Makes no linearization and no combination assumption, so it is the yardstick the cheaper rungs are validated against.

Lean code for Definition19.4.3●1 definition
  • defdefined in PropertyKindCalculus/Uncertainty/Mcm.lean
    complete
    def PropertyKindCalculus.Uncertainty.Mcm.run (model : List Float → Float)
      (inputs : List (PropertyKindCalculus.Uncertainty.InputDist Float))
      (n : ℕ) (seed : UInt64) : Float × Float
    def PropertyKindCalculus.Uncertainty.Mcm.run
      (model : List Float → Float)
      (inputs :
        List
          (PropertyKindCalculus.Uncertainty.InputDist
            Float))
      (n : ℕ) (seed : UInt64) : Float × Float
    **Monte Carlo propagation.** Returns `(E(Y), u(Y))` — the sample mean and (population)
    standard deviation of `model` over `n` joint draws of `inputs`, seeded by `seed`. 
Proof for Definition 19.4.3
uses 0

Realized. Mcm.run over the Float carrier, drawing each input through its invCDF. Efficiency is not its job — fidelity is.

Definition19.4.4
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 1✓L∃∀N

The sensitivity bridge: the coefficients c_i = \partial f/\partial X_i that GUM and Willink need are obtained by instantiating the write-once model at an autograd carrier and running one reverse pass at the input means — not by hand. This is the extract step of the two linearized rungs, and the narrow, precise role of automatic differentiation here, since the SSPRC method is derivative-free.

Lean code for Definition19.4.4●1 definition
  • defdefined in PropertyKindCalculus/Uncertainty/Sensitivity.lean
    complete
    def PropertyKindCalculus.Uncertainty.Sensitivity.gradient
      (model : PropertyKindCalculus.Uncertainty.Sensitivity.ScalarModel)
      (point : List Float) : Except String (List Float)
    def PropertyKindCalculus.Uncertainty.Sensitivity.gradient
      (model :
        PropertyKindCalculus.Uncertainty.Sensitivity.ScalarModel)
      (point : List Float) :
      Except String (List Float)
    **Reverse-mode gradient of a scalar model at a point.** Instantiates the write-once kernel at
    the tape carrier `TapeBuilder .scalar`, creating one differentiable input leaf per coordinate of
    `point`, records the forward tape, runs a single reverse pass from the scalar output, and reads
    back `∂f/∂xᵢ` at `point` in input order. These are the sensitivity coefficients `cᵢ` the
    linearized GUM/Willink methods consume (UNCERTAINTY.md §3.2 item 1).
    
    **Stage 3.5 retarget.** The reverse pass is the *total dense* engine entry
    `Tape.backwardDenseFrom` — the very function TorchLean's soundness theorem
    `backwardDenseFrom_lowerGraphToTape_adjoint_fderiv` (`NN/Proofs/Autograd/Runtime/Link/FDeriv.lean`)
    characterizes: on a compiled graph at the `ℝ` carrier, its input-prefix output is the adjoint of
    the Fréchet derivative of the forward evaluation. The seed is `1` at the scalar output and `0`
    everywhere else, which on a topologically-ordered tape computes the same accumulation as the
    previous reachability-pruned `backwardScalar` path (a dead subexpression now contributes an exact
    `0` instead of being skipped). The two honest gaps that remain are recorded in UNCERTAINTY.md
    §3.2/§6: this tape is built eagerly rather than by `lowerGraphToTape` (provenance), and it runs at
    `Float` while the theorem speaks at `ℝ` (the deviation is this workstream's own Adequacy claim). 
Proof for Definition 19.4.4
uses 0

Realized (Stage 1, Sensitivity.gradient; retargeted in Stage 3.5). The model kernel — the same source run at Float for Monte Carlo — is interpreted at TorchLean's reverse-mode TapeBuilder carrier; each input enters as a differentiable leaf, and one total dense reverse pass (Tape.backwardDenseFrom, seeded 1 at the scalar output) reads every c_i, with no model rewrite. Since Stage 3.5 this is the very entry point TorchLean's soundness theorem backwardDenseFrom_lowerGraphToTape_adjoint_fderiv characterizes: on a compiled graph at the ℝ carrier its input-prefix output is the adjoint of the Fréchet derivative of the forward evaluation (the eager-tape provenance — narrowed at Stage 3.6 to a closure-provenance question, see the direct-simulation theorem below — and the Float-vs-ℝ deviation remain the two documented gaps). On the Degenhardt fictive model the bridge returns (c_1, c_2, c_3) = (5, 5, 2.25) and reproduces the GUM u_c = 1.662 exactly (the DegenhardtSensitivity example). The op class is exp/log/sqrt with arithmetic; trigonometric models await tape VJP nodes.

Theorem19.4.5
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 0✓L∃∀N

Direct runtime simulation, closed for compiled tapes (Stage 3.6). The executable dense reverse pass on a compiled tape succeeds, and the input-prefix of its gradient array — the runtime's own shape-erased representation, block by block (ArrCorr) — realises exactly the adjoint of the Fréchet derivative of the forward evaluation applied to the seed. Separately, and for arbitrary (not just compiled) value-correct tapes: the reverse pass returns .ok provided every backward closure is shape-total — a hypothesis the eager leaf/add/mul tape constructors are proved to provide, constructor by constructor.

Lean code for Theorem19.4.5●1 theorem
  • theoremdefined in PropertyKindCalculus/Uncertainty/Experiments/PRSimulation.lean
    complete
    theorem PRSim.direct_PR_soundness_compiled {Γ ss : List Spec.Shape}
      (g : Proofs.Autograd.Graph Γ ss)
      (hg : Proofs.Autograd.GraphFDerivCorrect g)
      (x : TorchLean.TensorPack ℝ Γ)
      (seed : TorchLean.TensorPack ℝ (Γ ++ ss)) :
      ∃ out,
        (g.toAlgebra.lowerGraphToTape x ()).1.backwardDenseFrom
              seed.toShapeErasedArray =
            Except.ok out ∧
          PRSim.ArrCorr
            ((ContinuousLinearMap.adjoint
                (fderiv ℝ g.evalVec (Proofs.Autograd.flattenCtx x)))
              (Proofs.Autograd.flattenCtx seed))
            (out.extract 0 Γ.length)
    theorem PRSim.direct_PR_soundness_compiled
      {Γ ss : List Spec.Shape}
      (g : Proofs.Autograd.Graph Γ ss)
      (hg :
        Proofs.Autograd.GraphFDerivCorrect g)
      (x : TorchLean.TensorPack ℝ Γ)
      (seed :
        TorchLean.TensorPack ℝ (Γ ++ ss)) :
      ∃ out,
        (g.toAlgebra.lowerGraphToTape x
                    ()).1.backwardDenseFrom
              seed.toShapeErasedArray =
            Except.ok out ∧
          PRSim.ArrCorr
            ((ContinuousLinearMap.adjoint
                (fderiv ℝ g.evalVec
                  (Proofs.Autograd.flattenCtx
                    x)))
              (Proofs.Autograd.flattenCtx
                seed))
            (out.extract 0 Γ.length)
    **Runtime reverse pass on a compiled tape = `(fderiv ℝ evalVec x)†`, in `ArrCorr` form.**
    (The closure of the original `direct_PR_soundness`, for compiled tapes: a corollary of the
    Stage-3.5 endpoint; the `Γ`-prefix of the output array realises exactly the adjoint of the
    Fréchet derivative of the P graph's forward evaluation.) 
Proof for Theorem 19.4.5
uses 0

Realized (PRSim.direct_PR_soundness_compiled, with backwardDenseFrom_ok for the totality half and forwardSim_lowerGraphToTape inhabiting the simulation relation; Experiments/PRSimulation.lean, sorry-free). The endpoint is the input-prefix projection of the Stage-3.5 theorem transported to the runtime array by two erasure lemmas (block-reads invert context flattening; Array.extract is the erased typed prefix) — no reverse-pass fold argument is re-derived, so the adjoint mathematics enters exactly once, through the Stage-3.5 bridge. The totality half threads the "every slot carries its node's shape" invariant through the accumulation fold, value-free; the shape-totality hypothesis is honest and necessary, since a value-correct tape with an erroring closure refutes the unconditioned claim — the closure-provenance identification for the eager path is the next theorem. The AutogradDirectSim example instantiates everything concretely and pins the axiom profiles to the classical trio.

Theorem19.4.6
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 0✓L∃∀N

Eager provenance (Stage 3.6 addendum). The tape the eager runtime constructors actually build — input leaves, then one add/mul call per graph node, which is the construction pattern the sensitivity bridge uses — runs the same total dense reverse pass as the compiled tape of the corresponding graph: same result, same gradient array, from any erased-context seed. Therefore the Fréchet-adjoint endpoint above holds on the eagerly built tape itself, with no compilation anywhere in the trusted path.

Lean code for Theorem19.4.6●1 theorem
  • theoremdefined in PropertyKindCalculus/Uncertainty/Experiments/EagerProvenance.lean
    complete
    theorem PRSim.direct_PR_soundness_eager {Γ ss : List Spec.Shape}
      (g : Proofs.Autograd.Graph Γ ss)
      (hg : Proofs.Autograd.GraphFDerivCorrect g)
      (x : TorchLean.TensorPack ℝ Γ) {t : PRSim.RTape}
      (ht : PRSim.EagerBuilds g x t)
      (seed : TorchLean.TensorPack ℝ (Γ ++ ss)) :
      ∃ out,
        Runtime.Autograd.Tape.backwardDenseFrom t seed.toShapeErasedArray =
            Except.ok out ∧
          PRSim.ArrCorr
            ((ContinuousLinearMap.adjoint
                (fderiv ℝ g.evalVec (Proofs.Autograd.flattenCtx x)))
              (Proofs.Autograd.flattenCtx seed))
            (out.extract 0 Γ.length)
    theorem PRSim.direct_PR_soundness_eager
      {Γ ss : List Spec.Shape}
      (g : Proofs.Autograd.Graph Γ ss)
      (hg :
        Proofs.Autograd.GraphFDerivCorrect g)
      (x : TorchLean.TensorPack ℝ Γ)
      {t : PRSim.RTape}
      (ht : PRSim.EagerBuilds g x t)
      (seed :
        TorchLean.TensorPack ℝ (Γ ++ ss)) :
      ∃ out,
        Runtime.Autograd.Tape.backwardDenseFrom
              t seed.toShapeErasedArray =
            Except.ok out ∧
          PRSim.ArrCorr
            ((ContinuousLinearMap.adjoint
                (fderiv ℝ g.evalVec
                  (Proofs.Autograd.flattenCtx
                    x)))
              (Proofs.Autograd.flattenCtx
                seed))
            (out.extract 0 Γ.length)
    **The Stage-3.5/3.6 endpoint, on the eagerly built tape**: the dense reverse pass on the
    runtime-constructed `leaf`/`add`/`mul` tape succeeds, and the input-prefix of its output
    realises the adjoint of the Fréchet derivative of the graph's forward evaluation. 
Proof for Theorem 19.4.6
uses 0

Realized (PRSim.direct_PR_soundness_eager, via backwardDenseFrom_eager_eq_compiled; Experiments/EagerProvenance.lean, sorry-free). EagerBuilds is the provenance relation — its base tape is the compiled tape of the empty graph, definitionally — and the identification is pure accounting, never a re-derived fold: the compiled node's dense contribution list is folded by the upstream accumulation bridge, the eager node's sparse two-element list by a new single-slot lemma (one accumulation call is a one-hot context addition), and the two context updates coincide by flatten-injectivity through the vectorization homomorphisms — the eager closure's stored product-rule payloads are exactly the ofVec-authored node's Hadamard vjp blocks. Push-invariance lemmas restrict the extended tape's loop to its prefix, so the structural induction consumes its hypothesis directly. Honest residuals: ops beyond add/mul (one more crank of the same machine per op), the TapeM state-monad sugar (a one-line wrapper per op), and the Float-vs-ℝ deviation — the workstream's own Adequacy claim. The AutogradDirectSim example witnesses EagerBuilds for the concrete product tape and pins the classical-trio axiom profile.

Theorem19.4.7
Group: The uncertainty layer rests on one additive descriptor placed alongside a quantity's magnitude. It has two faces, matching its two consumers: carrier-parametric moment data (what the linearized methods consume and what the ℝ -level theorems are proved about), and a sampler (the inverse-CDF, the single primitive shared by the Monte Carlo and systematic methods). The support range is carried too, because it is exactly the datum the numerical-adequacy check needs — the architectural hinge that makes the two halves of this chapter one design. (36)
Group member previews
Preview
Definition 19.3.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0used by 1✓L∃∀N

Cumulant additivity (T1). Combining independent contributions adds their cumulants: the measurand's combined (\kappa_2, \kappa_4) for an input list is the head input's contribution plus the combined cumulants of the tail. Equivalently the contribution type is a commutative monoid under combine — and that it is a monoid is the independence assumption made explicit. This is Willink's \kappa_r(\sum_j a_j Z_j) = \sum_j a_j^{\,r}\,\kappa_r(Z_j) for r \in \{2, 4\}, the fact the whole ladder rests on.

Lean code for Theorem19.4.7●1 theorem
  • theoremdefined in PropertyKindCalculus/Uncertainty/Ladder.lean
    complete
    theorem PropertyKindCalculus.Uncertainty.willinkCumulants_cons
      (t : ℝ × PropertyKindCalculus.Uncertainty.MomentData ℝ)
      (ts : List (ℝ × PropertyKindCalculus.Uncertainty.MomentData ℝ)) :
      PropertyKindCalculus.Uncertainty.willinkCumulants (t :: ts) =
        PropertyKindCalculus.Uncertainty.termCumulants t +
          PropertyKindCalculus.Uncertainty.willinkCumulants ts
    theorem PropertyKindCalculus.Uncertainty.willinkCumulants_cons
      (t :
        ℝ ×
          PropertyKindCalculus.Uncertainty.MomentData
            ℝ)
      (ts :
        List
          (ℝ ×
            PropertyKindCalculus.Uncertainty.MomentData
              ℝ)) :
      PropertyKindCalculus.Uncertainty.willinkCumulants
          (t :: ts) =
        PropertyKindCalculus.Uncertainty.termCumulants
            t +
          PropertyKindCalculus.Uncertainty.willinkCumulants
            ts
    **T1 (fold form).** Prepending an input adds its contribution: the combined cumulants of
    `t :: ts` are `termCumulants t + willinkCumulants ts`. Independent contributions add — the
    cumulant-additivity theorem, realized through the `Cumulants` monoid. 
Proof for Theorem 19.4.7
uses 0

Realized over ℝ: willinkCumulants_cons, with the Cumulants AddCommMonoid instance (the combine/empty monoid laws) providing the associativity/commutativity/unit that make the independent fold well-defined.

Lean code for Theorem19.4.8●1 theorem