TorchLean

6.1. Verification🔗

When TorchLean says a model is verified, it means a specific check against a specific semantics. We pin down that meaning before talking about tools.

The scope is deliberately narrow. TorchLean targets a denotation defined in Lean, not a private interpreter and not an opaque export format whose meaning has to be reconstructed after the fact. That choice keeps the runtime, the verifier, and the proof scripts talking about the same object.

The verification layer is built around one symbolic IR, NN.IR.Graph, and then extended with bound propagation, certificate checking, and soundness proofs on top of that shared object.

The path is:

  • start from a TorchLean API program or imported model artifact;

  • compile or translate it to NN.IR.Graph plus a ParamStore;

  • run a checker such as IBP, CROWN, a certificate parser, or a scientific ML checker;

  • interpret the result through a theorem about the IR denotation, or through an explicitly named external boundary.

Concretely, the verification stack consists of:

  • a canonical op tagged IR (NN.IR.Graph),

  • executable verifier passes (IBP/CROWN bound propagation) that operate on that IR,

  • soundness theorems for a supported fragment, so "checked bounds" can mean something,

  • and explicit trust boundary patterns for integrating external artifacts like α,β-CROWN JSON.

A few names come up over and over in what follows:

  • IBP: interval bound propagation, where each node carries an interval box [lo, hi].

  • CROWN: a family of backward linear-relaxation methods that propagate affine bounds.

  • LiRPA: linear relaxation-based perturbation analysis, the broader family that includes IBP and CROWN methods.

  • IEEE32Exec: TorchLean's executable IEEE-754 binary32 kernel in Lean.

  • FP32: TorchLean's float32 model used in proofs, instantiated as rounded real semantics.

6.1.1. What TorchLean Verifies Today🔗

TorchLean's verification support is not one monolithic button. It is a set of related workflows with different claim strengths:

  • IR well formedness: checks that node ids, parents, shapes, and op payloads line up in NN.IR.Graph.

  • Compiler alignment: proves that a supported compiled IR evaluator matches the reference IR denotation.

  • IBP bounds: checks a graph, parameter store, and input box, then propagates interval boxes through supported nodes.

  • CROWN bounds: checks affine lower and upper forms for supported nodes or output margins.

  • JSON certificates: parses imported artifacts and either recomputes selected quantities or checks structural consistency, depending on the certificate family.

  • Float32 transfer: combines a real/spec theorem with an FP32 or IEEE32Exec error budget under explicit finite path assumptions.

  • CUDA backed runs: provide engineering validation and named assumptions for native kernels, not a Lean proof of every CUDA instruction.

The useful habit is to name the workflow and claim level. "Verified" should always come with a noun: verified shape check, verified IR compilation theorem, verified IBP enclosure, verified imported certificate, or verified float32 transfer theorem.

6.1.2. The Main Idea🔗

The same graph serves several roles at once. A model is compiled to an explicit symbolic IR graph (NN.IR.Graph); verifier passes such as interval bounds, affine bounds, and certificate checks run on that graph; and theorems talk about the graph denotation rather than about an opaque execution trace.

That gives us a useful vocabulary for the rest of the manual:

  • proved means Lean has a theorem about a semantic object defined in Lean.

  • checked means Lean recomputes or structurally validates an imported artifact.

  • assumed means the repository keeps the trust boundary visible instead of treating the missing piece as proved.

6.1.2.1. The Claim Ladder🔗

A good way to read TorchLean verification output is as a ladder:

  1. The file runs. This catches ordinary integration failures.

  2. The graph is well formed and well shaped. The symbolic object is structurally meaningful.

  3. A checker accepts an artifact. Lean has parsed and checked a concrete object.

  4. A theorem applies to the supported fragment. The accepted object implies a mathematical statement about the graph denotation.

  5. A scalar bridge applies. The theorem can be related to the runtime scalar path being claimed.

Skipping a rung is where overclaiming usually happens. For example, a CUDA training run may reach rung 1 and supply useful engineering evidence, but it does not by itself discharge the graph soundness theorem or the native-kernel trust boundary.

This is the bridge between a PyTorch style API and verification mathematics that can be stated and cited precisely.

6.1.3. Shared Semantic Target🔗

TorchLean is not just a verifier with a convenient front end. Runtime compilation and verification share one graph semantic target, the scalar semantics are explicit enough that floating point assumptions can be named rather than hand-waved, and certificate checking is separated into recompute-and-compare checks versus weaker structural checks of imported artifacts.

That perspective is why the examples cover several application families instead of a single minimal robustness case:

  • robustness and certified margins,

  • PINN residual bounds,

  • ODE enclosure and dynamical-system reasoning,

  • controller and Lyapunov two-stage workflows,

  • and benchmark oriented exported artifact checks such as VNN-COMP suites.

6.1.4. External Producers, Python, Julia, And FFI🔗

Verification workflows often need tools outside Lean. A Python verifier may optimize CROWN slopes, a Julia script may generate a scientific certificate, a PyTorch checkpoint may provide parameters, and a CUDA kernel may produce runtime values. TorchLean supports those workflows, but it does not turn the producer into a theorem merely because the producer ran.

The repository uses two patterns:

  • Process wrappers: external process helpers and Julia helpers resolve commands, run tools, capture JSON, and fail loudly when the external command is unavailable or malformed.

  • Artifact checkers: verification modules parse exported JSON, checkpoint-like parameter stores, ODE corridors, PINN residual certificates, CROWN node certificates, or α,β-CROWN leaf artifacts and check a precise predicate inside Lean.

That gives a clean division of labor. Python, Julia, CUDA, and external verifiers can search, train, optimize, and generate candidate artifacts. Lean checks the artifacts that have a specified format and theorem-backed meaning. If a workflow only runs an external tool and imports its answer without a recompute or proof-backed checker, the guide calls that an assumption boundary rather than a verified result.

6.1.5. From Bug Case Studies To Verification Obligations🔗

The BugZoo examples are not separate from verification. They are small versions of the same pattern: turn an informal failure mode into a precise obligation.

For example:

  • An attention-mask bug becomes a theorem about masked softmax weights.

  • A KV-cache bug becomes an append invariant over the final cache slot.

  • A tokenizer/config bug becomes an in-range token contract using Fin vocabSize.

  • A compiler wrong-code bug becomes a source-target semantic preservation obligation.

  • A float deployment bug becomes a bridge obligation from runtime float32 behavior to IEEE32Exec or FP32.

  • A CUDA fused kernel bug becomes a question of whether the native kernel refines the Lean spec.

That last item is exactly how to read FlashAttention in TorchLean. The spec theorem flashAttention_eq_scaledDotProductAttention says the fused proof object denotes ordinary scaled dot product attention. The native CUDA symbols are then tested and isolated behind the FFI boundary. So the verification claim is layered:

  1. the fused spec equals SDPA;

  2. the graph/compiler path uses the stated attention op;

  3. verifier passes reason about the supported graph fragment;

  4. the native CUDA kernel remains an external implementation that must be tested or separately proved against the spec.

This is our recurring habit: every strong claim should say which layer discharged it.

6.1.5.1. Reproducing The Geometry3D Detector Check🔗

The Geometry3D workflow is the same trust-boundary pattern with a real 3D vision model. WildDet3D is an untrusted producer: it emits a camera matrix, a 3D object box, and a 2D detection box. Lean is the checker: it parses the exported JSON, recomputes the projection, checks positive depth and image bounds, and proves via checkCert_sound that an accepted certificate satisfies the Verified3DBox predicate.

The light real-image path uses DETR plus Depth Anything V2:

python3 scripts/verification/regenerate_assets.py --group geometry3d-real --run
lake exe verify -- camera-box3d-cert _external/geometry3d/realworld/coco_cats_depth_box.json

The heavier actual-3D-detector path uses Ai2's allenai/WildDet3D model/Space:

python3 -m pip install -r scripts/verification/geometry3d/requirements-wilddet3d.txt
python3 -m pip install --no-deps utils3d
python3 scripts/verification/regenerate_assets.py --group geometry3d-wilddet3d --run
lake exe verify -- camera-box3d-cert _external/geometry3d/wilddet3d/wilddet3d_cat_box3d_cert.json

The WildDet3D group produces both an accepted projected-footprint certificate and a rejected strict model-bbox diagnostic. This is the important distinction: the detector can be useful, while its 2D/3D glue claim is still checked after export instead of trusted because the tensor came from a large model.

WildDet3D model bbox versus projected 3D footprint

6.1.6. LiRPA Family (The Unifying Pattern)🔗

Most practical neural network verifiers in the IBP/CROWN family are instances of LiRPA (Linear Relaxation-based Perturbation Analysis). The pattern is familiar: start with an input uncertainty set, usually a box or an l∞ ball; propagate an overapproximation of each node's value through the graph; and rely on induction over node order to turn local rules into a global guarantee.

TorchLean makes that pattern visible in the module structure. The shared object is NN.IR.Graph, the shared semantics is NN.IR.Graph.denote / NN.IR.Graph.denoteAll, and the verifier passes produce PropState artifacts such as IBP boxes and affine forms over that same IR.

This section focuses on the implemented IBP and CROWN affine layer, plus the way the repository keeps proved, checked, and assumed distinct.

6.1.7. IBP vs CROWN (What These Passes Actually Compute)🔗

TorchLean's core bound propagation passes follow the LiRPA family of methods, in which the verifier tracks an overapproximation through the graph instead of symbolically expanding every branch.

6.1.7.1. IBP (Interval Bound Propagation)🔗

IBP is the simplest sound pass:

  • Each node carries an interval box [lo, hi] for each scalar component of the node's tensor.

  • Each op has a local "interval transformer" that maps parent boxes to an output box.

Informally, IBP says:

if each parent value lies inside its parent box, then the node value lies inside the box produced

by the IBP transformer for that op.

This makes IBP cheap and robust, but also conservative. Over sufficiently deep nonlinear composition, intervals can widen quickly.

The key linear layer rule is sign splitting. For a row y_i = sum_j W_ij x_j + b_i, positive weights use the lower endpoint for the lower bound and the upper endpoint for the upper bound, while negative weights do the opposite. In a two input example with x1 in [0, 1], x2 in [-1, 2], and y = 3*x1 - 2*x2 + 0.5, IBP gives lower = -3.5 and upper = 5.5.

For ReLU, IBP uses monotonicity: if y in [l, u], then ReLU y lies in [max 0 l, max 0 u].

That is sound and extremely simple. The limitation is that after this step the verifier has forgotten which input directions made y large or small; it keeps only the interval endpoints.

6.1.7.2. CROWN / DeepPoly (Affine Bounds)🔗

CROWN passes carry affine upper and lower bounds with respect to a designated input, plus (typically) the IBP box as a fallback. Affine bounds are tighter than pure intervals, but:

  • they are more expensive,

  • they need per op linear relaxations (especially for nonlinearities),

  • and they often use IBP to seed slopes or guard cases.

TorchLean stores these objects in flattened form for efficiency and reuse across operators. In spirit, that design is closest to the DeepPoly/ERAN style of verifier.

The important difference from IBP is that CROWN keeps a symbolic linear envelope instead of only a box. A node is not merely "somewhere between lo and hi"; it is bounded by affine functions of the original input.

For linear layers, we reuse the same sign-splitting idea, but we split against the parent affine lower and upper forms rather than against raw interval endpoints. The AlphaCROWN certificate API contains this transfer rule, especially the linearBoundsFromAffine path.

For ReLU, the interesting case is the unstable interval l < 0 < u. The exact function is bent, so we enclose it with lines. The standard upper line has slope u / (u - l) and passes through (l, 0) and (u, u). The lower line can be either 0 or y. For example, if y in [-1, 2], the standard CROWN upper line has slope 2/3.

The lower line can be either 0 or y, both sound but useful in different downstream objectives. That small choice is the seed of α-CROWN.

6.1.8. A More Concrete Example: Certifying A Margin🔗

A typical robustness property is not "bound every logit independently" but "prove one logit stays above the others." If class 0 is supposed to win against class 1, the verifier works with the margin logit_0 x - logit_1 x and tries to prove that it is positive for every perturbed input.

IBP can bound logit_0 and logit_1 separately. For example, if logit_0 in [0.8, 1.4] and logit_1 in [0.2, 1.0], the safe margin lower bound is 0.8 - 1.0 = -0.2, so IBP cannot certify the property even though the two logits may be strongly correlated.

CROWN instead can backpropagate the linear objective logit_0 - logit_1 through the network and bound that margin directly. If the affine margin lower bound evaluates to 0.15 on the input box, then every input in the perturbation box keeps class 0 ahead of class 1 by at least 0.15.

This is why CROWN methods matter: they can preserve correlations that interval methods erase.

6.1.9. Worked Example: TorchLean, IR, and IBP (Tiny MLP)🔗

The simplest verification pipeline in TorchLean is easy to state: define a model with the TorchLean API, compile its forward pass to the canonical IR with operation tags (NN.IR.Graph), seed an input uncertainty set, run a verifier pass such as IBP, and then read off the output bounds at the output node id.

The runnable demo is TorchLean IBP, and the matching CLI entrypoint is lake exe verify -- torchlean-ibp.

Below is the essential core of that file, trimmed to the minimum needed to follow the pipeline:

import NN
import NN.Verification.TorchLean.Compile

open _root_.Spec
open Tensor
open NN.Tensor
open NN.API

open NN.MLTheory.CROWN.Graph
open NN.MLTheory.CROWN

def model : nn.Sequential (Shape.Vec 2) (Shape.Vec 1) :=
  nn.blocks.mlp 2 1 { hidden := [3], activation := .relu, seedBase := 0 }

def paramShapes : List Shape := nn.paramShapes model

def runOnce {α : Type} [Semantics.Scalar α] [Runtime.Scalar α] [DecidableEq Shape] [ToString α] : IO Unit := do
  -- Parameters in the order expected by `paramShapes`.
  let params : tlist.TList α paramShapes :=
    tlist!
      (tensorND! [3, 2] [0.1, 0.2, 0.3, 0.4, 0.5, 0.6]),
      (tensorND! [3] [0.1, 0.2, 0.3]),
      (tensorND! [1, 3] [0.7, 0.8, 0.9]),
      (tensorND! [1] [0.4])

  let compiled ←
    match NN.Verification.TorchLean.compileForward1
          (α := α) (paramShapes := paramShapes) (inShape := Shape.Vec 2) (outShape := Shape.Vec 1)
          (nn.program (model := model) (α := α)) params with
    | .ok c => pure c
    | .error e => throw <| IO.userError e

  -- Seed an input box x in [x0 - eps, x0 + eps].
  let x0 : Tensor α (Shape.Vec 2) := tensorND! [2] [0.5, 0.8]
  let eps : α := Runtime.ofFloat 0.1
  let rad : Tensor α (Shape.Vec 2) := Spec.fill eps (Shape.Vec 2)
  let xB : FlatBox α := { dim := 2, lo := Tensor.sub_spec x0 rad, hi := Tensor.add_spec x0 rad }

  -- Run IBP on the compiled IR + parameter store.
  let ps : ParamStore α :=
    { compiled.ps with inputBoxes := compiled.ps.inputBoxes.insert compiled.inputId xB }
  let boxes := runIBP (α := α) compiled.graph ps

  -- Read the output bounds.
  let some outB := boxes[compiled.outputId]! | throw <| IO.userError "IBP produced no output box"
  IO.println s!"output lo = {pretty outB.lo}"
  IO.println s!"output hi = {pretty outB.hi}"

Two TorchLean invariants are visible immediately:

  • The verifier consumes the same NN.IR.Graph the runtime can also interpret (one semantic target).

  • Parameters live in an explicit ParamStore keyed by node id, so verification never guesses weights.

The key takeaway from the code sample is:

  • compileForward1 makes the graph and its payload explicit,

  • runIBP reads that graph directly,

  • and the output bounds are only meaningful because both steps share the same semantics.

Smallest complete verifier command:

lake exe verify -- torchlean-ibp

6.1.10. α-CROWN and α,β-CROWN (Where They Fit)🔗

In the broader ecosystem, CROWN is usually paired with stronger linear relaxations for nonlinear ops and with a backward pass that tightens the bound for a particular output margin. TorchLean has the same general shape, but the implementation is split between a Lean LiRPA engine for a curated op set (NN/MLTheory/CROWN) and checkers that compare Lean recomputation to JSON artifacts exported from Python tooling (NN/Verification/Cert).

Here is the practical meaning of the Greek letters:

  • α chooses the lower relaxation slope for unstable ReLUs.

  • β carries branch/split information, usually ReLU phase information, from a branch-and-bound verifier.

For an unstable ReLU with pre-activation y in [l, u] and l < 0 < u, the lower bound can choose between the two obvious sound lines, ReLU y >= 0 and ReLU y >= y. α-CROWN generalizes this as a slope choice ReLU y >= alpha * y with 0 <= alpha <= 1.

Different alpha values give different final margin bounds. The external α-CROWN optimizer searches for good α values. TorchLean's Lean transfer rule does not pretend to have run that optimizer; it checks the result for a fixed set of α values and proves/checks that the transfer rule is sound when the α values are in range.

β-CROWN adds the branch-and-bound side. A ReLU that was unstable in the root box might become known on a branch:

  • -1: inactive phase, meaning y <= 0, so the ReLU transfer is exact with ReLU(y) = 0.

  • 0: unstable or unsplit phase, so the checker uses the CROWN or α-CROWN relaxation.

  • 1: active phase, meaning 0 <= y, so the ReLU transfer is exact with ReLU(y) = y.

TorchLean's current α,β checker uses exactly that narrow interpretation. In the α,β-CROWN certificate API, β is represented as a per node vector with entries -1, 0, or 1. The checker verifies that the requested phase agrees with the provided IBP pre-activation bounds:

  • active requires 0 <= lo,

  • inactive requires hi <= 0,

  • unstable imposes no extra phase condition.

Then the ReLU transfer becomes exact for active/inactive neurons and falls back to the relaxation for unstable neurons.

That boundary is explicit. The full external search loop that chooses branches, optimizes α values, and prunes the tree is still outside the formal boundary. The imported artifact is checkable at the boundary we can state precisely: dimensions, graph ids, per node affine bounds, α vectors, β phase vectors, and Lean recomputation of the local transfer rule.

There are two checker levels:

The α,β-CROWN two-stage workflow is developed in the Certificates and Two-Stage Workflows chapters. Here, the emphasis stays on the shared IR and on what "certificate check" means inside TorchLean.

6.1.11. More Worked Examples🔗

The fastest way to understand the verifier stack is to watch a few tiny networks go through the same logic used for larger graphs. These examples are intentionally small; their value is that every production-scale claim is made of these same local steps plus induction over the graph.

6.1.11.1. Example 1: IBP certifies a one-layer margin🔗

Suppose the input is one-dimensional: x in [0.9, 1.1], logit0 x = 2*x, and logit1 x = x + 0.4.

IBP gives:

  • logit0 in [1.8, 2.2],

  • logit1 in [1.3, 1.5].

The margin lower bound is 1.8 - 1.5 = 0.3.

So the verifier can certify class 0 over the whole input box. This is the pleasant case: the property is simple enough that interval endpoints are already decisive.

6.1.11.2. Example 2: IBP can lose a true correlation🔗

Now use a different pair of logits: x in [0, 1], logit0 x = x, and logit1 x = x - 0.1.

Mathematically, class 0 wins everywhere because the margin simplifies to 0.1.

But if IBP bounds the logits separately, it gets:

  • logit0 in [0, 1],

  • logit1 in [-0.1, 0.9],

  • margin lower bound 0 - 0.9 = -0.9.

That does not prove the property. Nothing is wrong with IBP; it is sound. The interval abstraction has discarded the fact that the same x appears in both logits. CROWN can keep the affine dependency and bound the margin directly:

For the margin objective, CROWN keeps the cancellation x - (x - 0.1) = 0.1.

So CROWN certifies the property with margin 0.1. Affine forms retain this dependency information; endpoint boxes alone do not.

6.1.11.3. Example 3: ReLU relaxation at an unstable neuron🔗

Consider x in [0, 1], y = x - 0.5, and z = ReLU y.

IBP first gives:

  • y in [-0.5, 0.5],

  • z in [0, 0.5].

The ReLU is unstable because y may be negative or positive. CROWN stores linear envelopes. The standard upper line over [-0.5, 0.5] is z <= 0.5 * (y + 0.5). Sound lower choices include z >= 0 and z >= y. The α-CROWN lower relaxation chooses an interpolating lower slope z >= alpha * y with 0 <= alpha <= 1.

If we only need a lower bound on z, alpha = 0 is often strongest on this box because it gives z >= 0. But downstream layers can flip signs or combine neurons, so the best α value is objective-dependent. That is why an external α optimizer can improve the final margin even though every local α choice remains a simple line.

6.1.11.4. Example 4: β splitting turns an unstable ReLU into exact cases🔗

The same ReLU can become easy after a split. Again take x in [0, 1], y = x - 0.5, and z = ReLU y.

At the root box, y in [-0.5, 0.5], so β must be 0 (unstable). Now split the input domain:

  • left branch: x in [0, 0.5], so y in [-0.5, 0];

  • right branch: x in [0.5, 1], so y in [0, 0.5].

On the left branch, β may say inactive (beta = -1) and the exact transfer is z = 0. On the right branch, β may say active (beta = 1) and the exact transfer is z = y.

This is the branch-and-bound intuition behind β-CROWN. A loose triangle relaxation is not the end of the argument; the input space can be split until ambiguous ReLUs become exact on each leaf. TorchLean's current checker does not trust the split just because a JSON file says so. It checks the β phase against the branch's IBP pre-activation bounds, then applies the exact active/inactive transfer when the phase is consistent.

6.1.11.5. Example 5: What a node certificate is proving locally🔗

For a ReLU node certificate, the checker is essentially asking:

Given parent affine bounds, a parent IBP box, an optional alpha slope, an optional beta phase, and claimed output affine bounds, Lean asks whether the local transfer rule recomputes the same output affine bounds.

If yes, that node's certificate is accepted. If every node is accepted in topological order, and the graph is in the supported semantic fragment, the proof declarations can lift those local checks to a global enclosure theorem. That is the heart of the design: small local checks, then a graph soundness argument.

6.1.12. Pointers To Deeper Chapters🔗

The verification tree is broad, so this section names the areas that need their own careful reading path rather than being compressed into one verifier slogan:

  • CROWN as objective dependent backward reasoning, not only forward node by node affine bounds.

  • The difference between a per node recompute certificate and a branch and bound leaf artifact.

  • Which ops have proofs today versus only executable/debuggable support today.

  • How derivative bounds support PINN and ODE workflows.

  • How BoundOps and directed rounding relate to real valued enclosures and float32 execution.

  • How imported PyTorch / VNN-COMP / α,β-CROWN artifacts become Lean objects instead of remaining opaque blobs.

  • How the proof declarations connect to the executable checkers: local transfer soundness, topo-order induction, and final property extraction.

The next sections cover the first few of those more concretely; the certificate and two-stage workflows cover the external artifact side.

6.1.13. Application Families In The Current Repository🔗

The verification tree covers several different application styles. They all reuse the same graph ideas, but they answer different scientific questions.

6.1.13.1. 1. Robustness and margin certification🔗

This is the most familiar verifier workflow for many ML readers:

  • seed an input perturbation region,

  • propagate bounds through the network,

  • check that the true class margin stays nonnegative.

Relevant tools and examples:

  • torchlean-robustness

  • digits

  • margin-cert

  • torchlean-ibp

This is the natural place to connect TorchLean to the adversarial-robustness literature and to the IBP / CROWN / LiRPA papers already cited below.

6.1.13.2. 2. PINN residual bounds🔗

The repository includes a meaningful PINN slice rather than only generic verifier infrastructure. The PINN code answers questions of the form:

Over a spatial or spatio-temporal box, how large can the PDE residual become, given bounds on

the network output and its derivatives?

The implementation is organized around the PINN CLI, the PINN certificate checker, the PINN dataset checker, and the commands pinn-cli, pinn-cert, and pinn-dataset-check.

This is one of the clearest places where TorchLean's derivative-aware graph propagation is doing something more specialized than standard image-classifier robustness.

6.1.13.3. 3. ODE enclosure verification🔗

The ODE stack answers a different question again:

Does a neural network satisfy subsolution / supersolution style inequalities for a differential

equation over a region?

Useful declarations and tools:

This is also one of the places where the proof layer and the numerical layer meet most directly: the executable checker runs over an explicit scalar backend, while the theorem interpretation still depends on the floating-point semantics trust boundary.

6.1.13.4. 4. External benchmark and ecosystem workflows🔗

Not every useful workflow in TorchLean starts from a model written natively in Lean.

Relevant tools and examples:

These workflows matter because they show how TorchLean interfaces with existing verifier ecosystems without treating "imported JSON" as already a theorem.

6.1.13.5. 5. Controller / Lyapunov two-stage workflows🔗

The Lyapunov and controller workflows are still more research-flavored than the smallest public demos, but they are important for understanding the paper's broader claim that the stack applies to dynamical systems as well as to classifier margins.

Useful declarations:

These declarations make the trust boundary explicit through oracle or certificate assumptions instead of hiding it inside a monolithic external script.

6.1.14. Core Data Structures (What The Verifier Actually Consumes)🔗

This section answers a simple question: what data do the verifier passes actually consume?

6.1.14.1. NN.IR.Graph (Structure Only)🔗

  • Graph is a DAG of Nodes.

  • Nodes store parents, an op tag OpKind, and a declared outShape.

  • TorchLean intentionally keeps values/parameters out of the graph, because different backends want different parameter stores.

6.1.14.2. ParamStore (Values, Weights, and Seed Input Boxes)🔗

ParamStore is a minimal, backend-friendly store of payloads keyed by node id:

  • inputBoxes: node id mapped to FlatBox seed regions for designated input nodes

  • constVals: node id mapped to constant tensors

  • linearWB: node id mapped to linear parameters (W,b)

  • matmulW: node id mapped to bias-free matrix multiply parameters

  • conv2dCfg: node id mapped to typed convolution payloads

Verifiers never guess parameters; they look them up in a store produced by a compiler or provided by the user.

The reason for the flattened representation is practical: it is easy to update node by node, easy to compare in tests, and easy to inspect when a bound behaves unexpectedly.

6.1.14.3. PropState (Per-Node Bound Results)🔗

PropState is the per node bound workspace used while debugging passes:

  • states[i] : NodeState stores:

    • shape : Shape (unflattened tensor shape),

    • ibp? : Option FlatBox (interval bounds if computed),

    • aff? : Option FlatAffine (affine form if computed).

Running a pass typically yields arrays of optional boxes or affine forms, which are then packaged into a PropState for reporting.

For debugging, the infoview widgets #crown_view and #bounds_tightness_view show quickly whether a pass populated the expected state.

#check NN.IR.Graph.checkWellFormed
#check NN.IR.Graph.checkShapes
#check NN.IR.Graph.checkInferredShapes
#check NN.IR.Check.wellFormed_iff
#check NN.IR.Check.wellShaped_iff
#check NN.Verification.TorchLean.Proved.compileForward1_wellFormed
#check NN.Verification.TorchLean.Proved.evalCompiledForward1_eq_evalForward1

6.1.15. Supported Proved Fragment (Today)🔗

The authoritative statement of the current proved IBP fragment appears at the top of NN.MLTheory.CROWN.Proofs.GraphCertSoundness API.

At present, the soundness development is centered on the core graph dialect used by the bundled TorchLean verification demos:

  • .input, .const, .detach

  • .add, .sub, .mul_elem, .relu

  • .linear, .matmul in the verifier dialect where weights live in ParamStore

  • .tanh, .sigmoid, .sin, .cos

This list matters because it distinguishes a bound that is merely executable from one that is backed by the proof layer. Demos that use operators outside that fragment can still be run and inspected, but their outputs should not be treated as proof claims without extending the soundness development.

The clean way to write this in a paper or note is:

  • cite the proved IBP fragment from the graph certificate soundness theorem when the claim is limited to the list above, or

  • cite the executable verifier implementation when the claim is outside the current theorem scope.

6.1.16. Certificates (Two Different Meanings)🔗

In TorchLean documentation, the word "certificate" is used in two related but importantly different senses.

6.1.16.1. Recompute and compare certificates (strong checking, in Lean)🔗

These are JSON artifacts that record some intermediate (or final) bound results, and then Lean recomputes the same step and accepts the JSON only if it matches within a tolerance (to account for decimal serialization of floats).

This pattern lets Lean re-run the same arithmetic and reject JSON that does not match:

  • the JSON is untrusted,

  • Lean recomputation is the source of truth,

  • and the checker fails loudly on mismatch, often printing both bounds for debugging.

Relevant declarations:

For CROWN node certificates, the imported JSON has four conceptual parts:

ctx    : which input node the affine forms are written against
ibp    : interval boxes used to choose/validate nonlinear relaxations
crown  : claimed affine lower/upper forms for each node
alpha  : optional ReLU lower-slope choices
beta   : optional ReLU phase choices, encoded as -1 / 0 / 1

The checker does not trust the claimed crown arrays blindly. For each node, it:

  1. reads the parent affine bounds already checked earlier in topological order,

  2. reads the parameters from ParamStore,

  3. recomputes the Lean transfer rule for that node,

  4. compares the recomputed affine bounds with the JSON bounds under an explicit tolerance,

  5. rejects the artifact if shapes, dimensions, phases, or numeric values disagree.

A tiny ReLU example shows the flavor. Suppose a ReLU node has pre-activation IBP box [-1, 2].

  • If the certificate says beta = 1 (active), Lean rejects it, because active would require 0 <= lo, but lo = -1.

  • If the certificate says beta = -1 (inactive), Lean rejects it, because inactive would require hi <= 0, but hi = 2.

  • If the certificate says beta = 0, Lean treats the ReLU as unstable and uses the CROWN/α-CROWN relaxation.

If another branch has box [0.3, 2], then beta = 1 is consistent and the transfer can use the exact active rule ReLU(y) = y. If a branch has box [-2, -0.1], then beta = -1 is consistent and the transfer can use the exact inactive rule ReLU(y) = 0.

6.1.16.2. What certificates do not mean🔗

Certificates are not a substitute for proof.

  • A recompute and compare certificate says Lean can independently check a claimed bound artifact.

  • A structural certificate says Lean can verify shape/consistency conditions and keep the trust boundary explicit.

  • Neither of these turns an arbitrary external solver into a fully internal theorem unless the solver's computation is itself exported in a checkable form.

6.1.16.3. Structural leaf artifacts (weak checking, explicit trust boundary)🔗

Some external workflows export "leaf artifacts" that are meaningful only relative to the verifier's internal semantics, for example a branch-and-bound leaf condition that says a subdomain may be pruned because a lower bound exceeds a threshold.

Lean can still parse these artifacts and check their declared structure. However, if the artifact does not include the computation that produced the bounds, then treating the artifact as sound necessarily leaves an explicit oracle or trust boundary in place.

The α,β-CROWN leaf checker handles that boundary and is exposed through lake exe verify -- abcrown-leaf.

6.1.17. Runnable verification workflows today🔗

All bundled verification workflows are registered in one CLI dispatcher, verify. See CLI Entry Points for the exact invocation shape and for the tool-listing convention.

First run: torchlean-ibp.

What these runs do, roughly:

  1. Build or import a TorchLean model.

  2. Compile the forward pass to NN.IR.Graph plus a ParamStore (weights, consts, and seed boxes).

  3. Run IBP and/or CROWN propagation over the IR graph.

  4. Report bounds and optionally check a simple postcondition.

For the "Two-Stage" path, which covers α,β-CROWN integration, consult the Certificates and Two-Stage Workflows chapters for the external artifact workflow.

6.1.18. How To Run The Curated Verification Examples🔗

All of the following are registered under the unified verification CLI; see the verification CLI API for the authoritative list and defaults:

  • TorchLean, IR, and IBP demo: torchlean-ibp

  • TorchLean, IR, and IBP plus CROWN demo (ops like softmax and mse_loss): torchlean-crown-ops

  • TorchLean "tiny transformer" demo: torchlean-transformer-ibp

  • Margin / robustness demos: torchlean-robustness, digits, margin-cert

  • PINN workflows: pinn-cert, pinn-cli, pinn-dataset-check

  • IBP/LiRPA certificate checkers: lirpa-mlp, lirpa-cnn, lirpa-attention, lirpa-gru, lirpa-encoder

  • External artifact structural checks: abcrown-leaf

  • ODE enclosure verification: ode

  • Geometry and spline certificates: camera-box3d-cert, spline-cert

  • End-to-end TorchLean MLP workflow: torchlean-mlp-workflow

  • Benchmark-style exported-artifact suite: vnncomp-mnistfc

6.1.18.1. Practical reading order🔗

Starting from a runtime demo, the suggested order is:

  1. Graphs and IR

  2. Floating-Point Semantics

  3. return here once the terms above are familiar

Starting from a certificate artifact, the suggested order is:

  1. Certificates

  2. Two-Stage Workflows

  3. the certificate checker API

Many tools accept an explicit JSON path as the first argument; the -- list output shows the default path.

6.1.19. Reference Map🔗

6.1.19.1. IR and compilation🔗

The "Graphs and IR" guide gives the full picture of the different graph representations and how they relate.

6.1.19.2. Bound propagation (IBP/CROWN)🔗

6.1.19.3. CLI registry🔗

6.1.19.4. Certificate checkers (JSON compare)🔗

  • certificate checker API: checks untrusted JSON artifacts by Lean recomputation with explicit tolerance comparisons.

6.1.19.5. Curated examples🔗

6.1.19.6. PINN and ODE application code🔗

6.1.19.7. Lyapunov / controller workflows🔗

6.1.20. Trust Boundaries (What Is Executable vs Proved vs Assumed)🔗

TorchLean marks three different kinds of claim explicitly:

6.1.20.1. 1) Executable in Lean (Fast Path)🔗

  • IR evaluation (NN.IR.Semantics API) is executable.

  • IBP/CROWN passes are executable (compute boxes/affine forms).

  • Many demos run on an executable float backend (IEEE32Exec by default).

This tier is excellent for debugging and for checkable artifacts, but execution alone does not establish why a bound is sound.

6.1.20.2. 2) Proved Soundness (For a Supported Fragment)🔗

TorchLean has a soundness proof development for a supported subset of the graph dialect:

Informal theorem shape:

If every node in the graph is in the supported fragment and each local IBP transformer encloses

the op semantics, then the propagated boxes enclose the denotation of the whole graph (by

induction over node ids / topo order).

This is the standard "local soundness + induction over a DAG" structure that scales as more ops are added.

Important caveat: Some operator enclosures, especially for transcendentals, are implemented as heuristics and are explicitly marked as not enclosure sound. For a proof quality enclosure layer, prefer the operators covered by the soundness theorem and treat the rest as work in progress.

6.1.20.3. 3) Imported Artifacts (Externally Produced Certificates)🔗

When a certificate produced by an external verifier such as α,β-CROWN is imported, Lean can still:

  • parse it,

  • check it is structurally consistent (dimensions, ids, declared property form),

  • and connect it to downstream theorems under an explicit assumption boundary.

Lean does not automatically re-run α,β-CROWN unless the computation is also exported in a checkable form and verified inside Lean.

TorchLean is explicit about what is proved in Lean and what is checked as an external artifact:

  • If a verifier recomputes bounds inside Lean over an executable scalar backend, then the main remaining trust boundary is that the scalar backend matches its intended semantics.

  • With an imported external certificate, Lean can still check structural consistency, but it does not automatically validate the bound computation unless that computation is exported and checked as well.

The certificate guide documents the current minimal JSON leaf certificate format (v0.1) used in the Two-Stage path.

6.1.21. Informal theorem shapes (for citations)🔗

This section stays informal. It records the main guarantee shapes that papers and talks often need, with pointers to the precise Lean theorems.

6.1.21.1. Compiler-to-IR Alignment (Proved Fragment)🔗

Lean source: TorchLean compile proof fragment

In words (forward fragment only):

Compiling a forward program to IR preserves meaning:

evaluating the compiled IR graph equals evaluating the forward program's spec evaluator.

In code, look for the compile-forward theorem in the Correctness namespace. Its name starts with evalCompiledForward1 and ends with eq_evalForward1.

6.1.21.2. IBP Soundness Over the Graph Dialect (Supported Subset)🔗

Lean source: graph certificate soundness

In words:

If runIBP produces boxes for all nodes in a supported graph, then for any input x in the

seeded input box, the true denotation of every node lies within its IBP box.

This is the main "interval bounds cover true values" theorem surface for the proved subset. The Lean source to cite is graph certificate soundness.

6.1.21.3. Informal soundness statement (the one-liner)🔗

For a supported graph fragment, the central IBP soundness claim has this informal shape:

Assume g : NN.IR.Graph is well formed and uses only supported ops, ps : ParamStore provides the required payloads and input seed box, every local transformer used by runIBP encloses the corresponding IR op semantics, and the scalar backend matches its intended meaning. If st := runIBP g ps produces per node interval boxes, then every input in the seed box evaluates to values that lie inside the corresponding ibpBox st i for each node i.

The actual proof in the repo is a standard "local soundness + induction over node ids" argument implemented in NN.MLTheory.CROWN.Proofs.GraphCertSoundness API.

6.1.21.4. Exact theorem names worth citing🔗

Theorem names that are often cited first:

#check NN.MLTheory.CROWN.Graph.CertSoundness.cert_encloses_semantics
#check NN.MLTheory.CROWN.Graph.CrownCertSoundness.crown_checker_encloses_semantics
#check NN.MLTheory.CROWN.Graph.AlphaCrownTransferSoundness.alphaCrown_transfer_sound
#check NN.MLTheory.CROWN.Graph.AlphaCrownTransferSoundness.alphaBetaCrown_transfer_sound

Interpreted as a progression:

  • cert_encloses_semantics is the IBP enclosure theorem for the supported graph dialect;

  • crown_checker_encloses_semantics is the corresponding CROWN checker theorem;

  • alphaCrown_transfer_sound and alphaBetaCrown_transfer_sound are the transfer-soundness theorems for connecting external α-CROWN / α,β-CROWN style artifacts to the Lean semantics.

6.1.21.5. Certificate Checking (External Artifact Boundary)🔗

Reference declarations:

In words:

If Lean accepts a leaf certificate artifact, then the leaf's stated prune/verified condition

holds under the certificate's declared semantics and any explicit oracle assumptions.

This is the intended shape for integrating external runs without treating them as already proved.

Two theorems that line up compilation and evaluation:

#check NN.Verification.TorchLean.Proved.compileForward1_wellFormed
#check NN.Verification.TorchLean.Proved.evalCompiledForward1_eq_evalForward1

Related manual pages: Graphs and IR (IR definition), Floating-Point Semantics (scalar backends), Certificates and Two-Stage Workflows (α,β-CROWN artifacts).

6.1.22. References🔗

Bound propagation / LiRPA family:

  • IBP: Gowal et al., "On the Effectiveness of Interval Bound Propagation for Training Verifiably Robust Models" (ICCV 2019). https://arxiv.org/abs/1810.12715

  • CROWN: Zhang et al., "Efficient Neural Network Robustness Certification with General Activation Functions" (NeurIPS 2018). https://arxiv.org/abs/1811.00866

  • DeepPoly / ERAN-style abstract interpretation: Singh et al., "An Abstract Domain for Certifying Neural Networks" (POPL 2019). https://arxiv.org/abs/1812.02648

  • LiRPA on general computational graphs: Xu et al., "Automatic Perturbation Analysis for Scalable Certified Robustness and Beyond" (NeurIPS 2020). https://arxiv.org/abs/2002.12920

  • β-CROWN / α,β-CROWN: Wang et al., "Beta-CROWN: Efficient Bound Propagation with Per-neuron Split Constraints ..." (NeurIPS 2021). https://arxiv.org/abs/2103.06624

Related robustness-verification background:

  • Wong and Kolter, "Provable defenses against adversarial examples via the convex outer adversarial polytope" (ICML 2018). https://arxiv.org/abs/1711.00851

Ecosystem tool TorchLean interoperates with:

  • α,β-CROWN codebase: https://github.com/Verified-Intelligence/alpha-beta-CROWN

Application and benchmark references:

  • PINNs: Raissi, Perdikaris, and Karniadakis, "Physics-informed neural networks" (JCP 2019). https://arxiv.org/abs/1711.10561

  • ODE enclosure workflow inspiration: Tanaka and Yatabe, learn-and-verify style ODE enclosures, arXiv:2601.19818. https://arxiv.org/abs/2601.19818

  • VNN-COMP ecosystem: competition pages and benchmark suite material. https://sites.google.com/view/vnncomp