Lean 4.32, Numerical Proofs, and Runtime Tests
Imports, floating point, training, CUDA, and documentation
The July work touched most of TorchLean. We removed duplicate entry points, generalized tensor
operations, reorganized the floating-point files, and tested the training runtime on models large
enough to expose bugs that the small examples never reached.
Imports and File Layout
Most model code starts with import NN.API. The old NN.Library and NN.Entrypoint.* forwarding
modules are gone. Focused imports such as NN.Spec, NN.Runtime, NN.Floats, and
NN.Verification still lead directly to their declarations. The model zoo remains part of
TorchLean.
We also broke up several files that had become difficult to navigate. Training, data handling,
schedulers, CROWN propagation, graph lowering, runtime operations, normalization, Muon, and
floating-point semantics moved into smaller modules with narrower imports. The API tree is about
300 lines smaller and the guide is more than 5,000 lines shorter. The proof tree grew to include
numerical certificates, rounded backpropagation, optimizer contracts, and new floating-point
results.
The public neural-network API has one owner. Seeded layer builders and model-zoo constructors are
declared under TorchLean.nn; NN.API gathers them without redeclaring their names.
Fixed-sample training lives under TorchLean.Trainer.FixedSample. Inside the runtime, mutable
parameter storage and optimizer checkpoint schemas have their own modules, separate from trainer
execution and CUDA Adam serialization.
General tensors
A batch is an axis of a tensor. Permutation, reduction, reshape, and global average pooling
work over declared axes. Channel normalization takes an explicit channel axis and preserves
every other axis.
Models
CNNs, ResNets, ViTs, FNOs, transformers, GPT, Mamba, recurrent models, generative models,
reinforcement learning, and self-supervised examples all remain available. They use the
same tensor and layer API instead of carrying model-specific forwarding stacks.
Training
Optimizers share one stateful tensor interface. We kept laws that say something useful
about update rules and stream composition, and removed generated tables and `rfl` theorems
that only repeated a definition.
The trainer treats batchSize as the number of dataset items per optimizer update. For
an ordinary dataset those items are samples. For Data.batchDataset, each item is already a typed
tensor minibatch, so batchSize := 1 keeps one vectorized pass per update. Larger values accumulate
gradients across several items. Logged pre-update loss comes from the same forward tapes as the
gradients; training no longer runs a second forward pass just for logging.
Transformer batches use one attention tape node instead of asking the host to run the layer once
per sample. The public model and typed graph preserve the declared leading shape. The eager CUDA
path may fold those axes together with the attention heads for batched matrix multiplication, while
TorchLean still applies the hard mask and computes the local VJP. A regression compares the
vectorized forward value, input gradient, and shared weight gradients with repeated single-sample
execution.
Layer normalization and tanh-approximate GELU follow the same rule: one TorchLean operation,
one local VJP, and fused CUDA kernels for the numerical work. In a two-step GPT-2-small trace with
batch 6 and context 1024, local profiling showed fewer kernel launches while leaving the
matrix-multiplication schedule unchanged. The CUDA parity suite checks forward values and gradients
against the CPU path; the native kernels remain inside the documented runtime boundary. Timing
claims belong with a retained benchmark configuration and trace, so this update records the
implementation and regression coverage rather than presenting one workstation run as a general
speedup.
Matrix backward no longer materializes transposed copies before calling cuBLAS. The runtime
passes logical transpose flags to the same batched-matrix primitive used by linear layers,
projection weights, and ordinary matmul. Focused traces confirm that these temporary transpose
kernels disappear, and parity tests compare the resulting forward values and gradients with the
existing path.
CUDA Adam and AdamW state can be saved independently of model checkpoints. The binary
format records optimizer hyperparameters, parameter shapes, mutability flags, moment tensors, and
step counters using explicit little-endian fields. Loading rejects mismatched models, changed
moment parameters, duplicate state entries, truncation, and trailing data. Writes close and flush a
fresh sibling file before renaming it over the destination. The parameter-schema codec is shared by
backend-owned optimizer checkpoints; the CUDA Adam-family codec supplies the format-specific
configuration and moment payload.
Discrete model inputs have their own typed path through programs, modules, evaluators,
trainers, and checkpoints. CharGPT passes token ids and targets as bounded
Tensor (Fin vocab) [batch, seqLen] values; raw Tensor Nat [batch, seqLen] values are admitted
only after Tensor.checkIndices validates the tokenizer boundary. The old
floating-point transport and conversion step are gone. The causal Transformer API supports either
an independent vocabulary head or an output projection tied to the embedding table. In the tied
form, lookup and output gradients accumulate into the same parameter.
Floating-Point Semantics
import NN.Floats provides formats, rounding, finite binary32 semantics, executable IEEE binary32
operations, interval rounders, and scalar quantization. It does not pull in tensors, models,
autograd, CUDA, certificate checkers, or external tools. Tensor and proof integrations sit above
that import, while optional Arb checks require an explicit import.
The generic development under NN.Floats.NeuralFloat is organized by format, rounding, scalar
operations, analysis, error bounds, and execution policy. It covers radix and exponent formats,
directed and nearest rounding, round-to-odd, ULPs and neighboring values, double rounding, Sterbenz
subtraction, and absolute and relative error bounds. Flocq influenced the layout. TorchLean’s
definitions and proofs are written in Lean.
Sterbenz subtraction covers gradual underflow and has a binary32 specialization. Every finite
IEEE32Exec bit pattern is proved representable in that specification, so the executable Sterbenz
theorem can identify nearby subtraction with the exact real difference. Finite executable values
also expose a checked ULP exponent, and an absorption theorem connects an unchanged binary32
accumulator to the rounded-real specification.
We use the following distinction throughout TorchLean:
NeuralFloat and NF describe configurable rounded-real arithmetic used in proofs;
FP32 specializes the rounded-real model to binary32-sized parameters;
IEEE32Exec models executable IEEE-754-style binary32 behavior, including special values;
- runtime bridges state how native values are interpreted by those models.
The effective-rounding example shows the whole argument on one value: choose a format and rounding
mode, perform the rounding, and derive the resulting error bound. The runtime-approximation proofs
then start from the ideal autograd theorems and make every extra hypothesis about rounded execution
explicit.
Whole-Graph Numerical Certificates
TorchLean can build a numerical trace over the canonical NN.IR.Graph. Source intervals use
exact binary32 endpoints. The checker reconstructs
outward-rounded ranges for supported arithmetic, activations, directed square root, reductions,
matrix multiplication, pooling, MSE, and stable softmax; malformed domains and non-finite ranges
fail at the node that produced them.
Range rules live in an operation registry. The same traversal handles any architecture after
lowering. Before propagation, a coverage pass lists
the exact nodes whose primitives lack a range contract. Custom registries are named and the name is
stored in the certificate, so an artifact cannot be replayed under a different set of rules.
The same certificate contains the kernel-selection audit. Rounding mode, subnormal behavior,
FMA/contraction, and reduction order are recorded by each kernel capsule. Portable accumulations
use the fixed left fold from the tensor semantics. CUDA and LibTorch accumulations are marked
implementation-dependent, so their matrix products, convolutions, normalizations, FFT/FNO paths,
scans, and attention kernels cannot accidentally inherit a proof for a different reduction order.
The bit-level replay evaluates every graph intermediate with IEEE32Exec, checks its shape and
range, and rejects NaN or infinity. A checked certificate stores the exact graph it was checked
against, so replay cannot substitute a different graph. A separate proved real execution supplies
the semantic enclosure; combining it with the bit-level replay yields an entrywise error trace for
every node. The deep-dive example includes successful arithmetic, reduction, matmul, LayerNorm,
abs -> sqrt, and softmax traces, together with deliberately tampered, invalid-domain, and
wrong-reduction-policy cases. It ends with a complete two-layer MLP: ten graph nodes pass
coverage, range generation, backend-capsule audit, and bit-level replay. The
numerical-runtime walkthrough follows that
run from source enclosures to its checked output.
Rounded Backpropagation and Optimizers
The numerical proof continues past the forward graph. Proof-bearing reverse nodes carry both
their ideal VJP and their rounded VJP error transformer. The global reverse theorem composes those
local bounds through gradient accumulation and connects the result to executable autograd
GraphData.
One optimizer contract carries the gradient error through parameter updates. SGD and momentum SGD
have no extra domain condition. AdamW uses the same interface, with step data recording errors from
both moments, bias correction, square root, adaptive division, decoupled weight decay, and the final
subtraction; explicit margins keep the rounded denominator away from zero. The end-to-end theorem
therefore works unchanged for all three optimizers and for every model represented by a RevGraph.
A model-wide update applies it at each typed parameter index.
The canonical NN.IR.Graph certificate remains a forward certificate. Its current lowering does not
attach proved VJPs, so backward claims use the proof-bearing reverse graph path instead of silently
attributing autograd semantics to a forward-only lowering.
Tensor Quantization
Uniform affine quantization has one scalar definition under NN.Floats.Quantization and one
rank-polymorphic tensor adapter under NN.Spec.Quantization. The proofs cover code-range
preservation, monotonicity, exact dequantize/quantize round trips for in-range integer tensors, and
the half-step reconstruction bound when saturation is inactive. Layout and storage width are not
part of the arithmetic: int8, uint8, int4, and custom code sets differ through their integer bounds
rather than separate image-specific APIs.
Backend Contracts
Backend planning now records device, provider, operation, contracts, and evidence separately, then
binds each accepted capsule to a matching runtime handler. Unavailable providers fail explicitly,
and proof-carrying implementations retain their refinement theorem instead of relying on a trust
label. The backend chapter
contains the maintained profiles and full contract model; the
GPU chapter
covers native execution and platform boundaries.
Mathematical and Verification Corrections
Losses and masks
Huber loss and Smooth L1 have their intended, distinct scaling. Hard attention masks use
exact exclusion in the softmax semantics: a blocked entry contributes zero numerator. The old
finite -1000 masking convention was removed from attention paths and examples.
Bounds
Leaky-ReLU interval propagation handles a negative slope across the kink at zero. Logarithm
interval checks reject nonpositive domains. Unsound or undocumented GELU and ELU candidate
bounds were removed instead of being exposed under names that suggested certified enclosure.
Certificates
JSON certificate readers reject non-finite claims before array comparisons. IBP certificates
are checked by recomputing the complete IEEE32Exec trace from the trusted graph,
parameters, and input box; an artifact may widen that trace but may not shrink it. CROWN and
$\alpha,\beta$-CROWN affine entries are compared exactly with a sequential replay instead of being
propagated from certificate-supplied parents. A theorem turns successful exact replay into
the local-consistency proposition used by the generic CROWN soundness development. Relating that
binary32 replay to real-valued enclosure still requires the stated finite-precision refinement
assumptions.
Classical models
HMM normalization records zero probability for an impossible observation, and log-likelihood
is partial at that boundary. GMM covariance matrices must be symmetric positive definite,
mixture weights must be positive and normalized, and singular inversion fails rather
than returning the identity. The covariance gradients use the transpose-correct formulas.
Attention and diffusion
Multi-head attention reshapes sequence data to
(sequence, heads, head-dimension) before exchanging the sequence and head axes.
The probability-flow ODE uses the required one-half score coefficient, and its Euler sampler
visits time points in descending order from the noisy endpoint.
Layer and model edges
Dropout is the identity in evaluation mode. Max pooling rejects padding configurations that
would create windows containing no input values. PCA requires at least two samples for its
unbiased covariance and exports the centering term as a linear bias. Linear SVM fitting calls
its regularization coefficient lambda, leaving C for the standard
inverse-strength convention.
Formats and smooth pooling
A radix carries a proof that its base is at least two, and a format precision carries a
proof that it is positive. Checked constructors reject bad integers at configuration
boundaries. Smooth max pooling uses a sign-aware pivot for both positive and negative
inverse temperatures on CPU and CUDA. Zero, non-finite, or unrepresentable inverse
temperatures are rejected before a native kernel runs.
Rounded CROWN no longer discards every backward objective to a constant interval. For algebraic
nodes it carries lower and upper coefficient vectors with directed arithmetic, including the sign
of each input interval when the final affine form is evaluated. Nonlinear or unsupported nodes
still fall back to their checked IBP boxes. This improves the executable bound without pretending
that an unproved floating-point transfer is exact.
The arithmetic interface separates implementation from proof. BoundOps provides executable
lower and upper operations; LawfulBoundOps proves that those operations enclose exact real
addition, subtraction, and multiplication. Real and FP32 endpoints have lawful instances. Host
Float remains an explicitly trusted execution boundary, while IEEE special values are handled by
finite-path theorems instead of a blanket ordered instance.
The Lyapunov workflow no longer contains a repository-wide oracle axiom. Python output records a
region and numerical margins, and generated Lean files may prove arithmetic facts about those
numbers. A stability theorem additionally requires LyapunovCert.ValidFor, whose fields prove that
the reported intervals enclose the named Lyapunov function and orbital derivative throughout that
region.
The graph evaluator and verifier lowering are split by operation. Their coverage theorems still
range over the full operation vocabulary, so adding a new file does not weaken the statement being
proved. We removed theorems tied to incidental list lengths and retained small definitional lemmas
only when later correctness proofs actually use them.
Convolution, transposed convolution, fixed-window pooling, and adaptive pooling now share
channel-first contracts parameterized by spatial rank. Their public APIs take vectors of kernel,
stride, padding, and output dimensions; the same definitions therefore cover lines, images,
volumes, and higher-dimensional grids. The IR, eager runtime, CUDA path, and shape inference use
these contracts without separate rank-named wrappers. A semantic-preservation theorem connects
typed convolution lowering to forward IR evaluation. The exact derivative theorem covers the same
rank-polymorphic operation and proves the input, kernel, and bias reverse rules. Rounded-real
theorems bound every forward and backward coordinate using the implementation’s actual accumulation
order. BatchNorm now has the corresponding arbitrary-spatial-rank adjointness theorem for its input,
scale, and bias gradients.
PyTorch graph import now preserves every leading dimension of a linear layer. In particular, a
batched input of shape [3, 4] passed through Linear(4, 1) is imported with output shape [3, 1]
rather than [3]. The runtime check includes this case alongside arbitrary-axis reductions,
permutations, normalization, convolution, pooling, and attention, while continuing to reject
unsupported operator semantics explicitly.
Verification artifact readers share one finite box-region parser. It rejects non-finite
coordinates, negative radii, mismatched dimensions, reversed intervals, incomplete field pairs,
and mixed endpoint/center schemas. Format-specific checkers can require the exact endpoint schema;
the alpha-beta-CROWN leaf checker does so before checking nesting and threshold witnesses.
Lean 4.32
TorchLean builds with Lean, mathlib, DocGen, and Verso 4.32. During the upgrade we replaced the
deprecated Lean.RBMap with Std.TreeMap, used mathlib’s stronger sine remainder estimate, and made
several dependent casts explicit. Proof-valued runtime helpers are theorems when they serve as
opaque evidence; constructors that must compute remain reducible abbrevs. We fixed the new
linters rather than suppressing them.
Runtime Scaling and CUDA Ownership
The small examples had hidden an expensive habit: large parameters were first expanded into nested
Lean values and only then copied into the execution engine. Parameters and gradients are
materialized directly where they will run. We also stopped generic convolution backward from
rebuilding the same derivative structure, and taught CUDA attention and fused FNO paths to release
temporary buffers as soon as their contribution is consumed.
The most useful failure came from sparse reverse mode. A pure expression allocating a one-element
CUDA seed could be shared by Lean, even though backward consumed and released the native buffer.
The next use then referred to storage that was no longer alive. Seeds that cross an ownership
boundary come from an effectful constructor, and transfers between gradient maps use explicit
copy-and-release operations. A stress test repeats this path and fails if live CUDA allocation
grows or a supposedly fresh seed is reused.
A second lifetime problem was in the FFI signatures themselves. Buffer and array inputs were being
passed as owned Lean objects to native functions that treated them as borrowed, so neither side
released the wrapper reference. The declarations mark those inputs as borrowed. Separate
payload and wrapper counters make the distinction visible, and the stress suite checks thousands
of allocations for matching finalization counts.
Shape-erased CUDA values compare the native buffer length with the recorded tensor shape before
an operation runs. Dense and sparse backward also reject output seeds or initial gradients with the
wrong length. The stress suite covers each rejected case.
We exercised 21 CPU workflows and 24 CUDA workflows, including dense, convolutional, attention,
recurrent, operator-learning, generative, and reinforcement-learning models. On the machine used
for this release, a roughly 100-million-parameter MLP completed ten CUDA optimizer steps in about
15.2 seconds. The fused Burgers FNO ran for 100 steps with no growth in live buffers; training MSE
fell from 0.3260 to 0.0172 and test MSE ended at 0.0220. These numbers record what we tested on one
machine. They are not a general performance promise.
Documentation and Validation
The Guide and API reference follow the new module layout. Installation has separate notes for
Linux, macOS, WSL2, native Windows, CUDA, and optional LibTorch support, and the floating-point and
backend chapters explain where a theorem ends and a runtime assumption begins. Repository checks
build NN directly; NN.Library no longer exists.
Lyapunov results consume an explicit LyapunovCert.ValidFor proof, so a producer’s JSON flags
cannot become a stability theorem by themselves.
The Graphs page contains the module-import explorer and build-performance link. The Tools page links
LeanProfiler and TorchLean Verified Examples. LeanProfiler includes a TorchLean model run, Perfetto
trace output, and JSON comparisons. The verified examples cover batch-invariant inference and a
verifiable transformer checkpoint.
The import explorer ignores fenced guide examples, so an import shown in a tutorial is not
mistaken for a source-module dependency.
Wide tables are wrapped during the documentation build, and the Guide’s equations render with
KaTeX.
Validation
lake lint
lake build
lake build NN NN.CI.All
lake exe nn_tests_suite
lake -R -K cuda=true exe nn_tests_suite
scripts/checks/example_regression.sh across all registered commands and examples
scripts/checks/example_regression.sh --cuda --extended-cuda --skip-help --skip-default
- sustained 20-update CPU runs across 21 model workflows
- sustained 100-update CUDA runs across 24 model workflows
- repeated sparse-backward ownership and allocator-drift regression
- external-wrapper allocation/finalization regression on both the CUDA and CPU-stub builds
- NVIDIA Compute Sanitizer memcheck (
ERROR SUMMARY: 0 errors)
- DocGen API generation
- Verso Guide generation
- dependency audit and interactive import-graph generation
- Jekyll production build
git diff --check
All of these checks passed on the Linux machine used for the release. That gives us evidence for the
paths we exercised, but it does not turn CUDA machine code or LibTorch into Lean proofs. Their trust
levels remain explicit in the backend contracts and in TRUST_BOUNDARIES.md.