Installation
If you want to try TorchLean on a laptop, start with the CPU build. It does not require PyTorch,
CUDA, or a GPU. The repository pins its Lean version in lean-toolchain, so Elan will select the
right compiler for you.
A Five-Minute CPU Install
First install Elan, the Lean toolchain manager. On Linux or macOS:
curl https://elan.lean-lang.org/elan-init.sh -sSf | sh
Open a new terminal so that elan, lean, and lake are on your PATH. Then clone and build
TorchLean:
git clone https://github.com/lean-dojo/TorchLean.git
cd TorchLean
lake exe cache get
lake build
The cache command downloads compatible prebuilt Lean dependencies when they are available. It is
safe to omit; lake build will compile anything that is missing.
Run a small model to check the executable path:
lake exe torchlean quickstart_mlp --device cpu --steps 10
If those commands succeed, TorchLean is installed. You can inspect the available examples and verification commands with:
lake exe torchlean --help
lake exe verify --help
That CPU build is the common starting point on every platform. From there, TorchLean can compile its native CUDA runtime or link an external provider without changing the Lean model being run. The table below separates paths that work today from targets that are represented in the backend architecture but still need platform-specific runtime work.
| Platform | CPU | NVIDIA GPU | LibTorch provider | Current status |
|---|---|---|---|---|
| Linux | ✓ | ✓ Native CUDA | Standalone CUDA SDPA bridge test | Supported; LibTorch eager dispatch is not wired |
| macOS, Intel or Apple silicon | ✓ | Not applicable | Not yet | CPU supported; Metal is planned |
| Windows with WSL2 | ✓ Linux path | ✓ CUDA on WSL2 | Linux path | Recommended Windows setup |
| Native Windows | Bring-up target | Not validated | Not wired | Backend target exists; native toolchain work remains |
Here, “LibTorch provider” means the current scaled-dot-product-attention bridge, not a requirement for ordinary TorchLean models and not a claim that every operation is delegated to PyTorch. The CPU, native CUDA, and LibTorch sections below give the corresponding build commands.
Linux
CPU
You need Git, curl, and a C/C++ compiler. On Ubuntu or Debian:
sudo apt update
sudo apt install -y git curl build-essential
Then follow the five-minute install above. The default build uses the portable CPU runtime. It also builds harmless CUDA stub archives so that CPU-only machines can compile the complete Lean project; the stubs do not pretend that a GPU is present.
NVIDIA CUDA
Install a supported NVIDIA driver and CUDA toolkit using NVIDIA’s
CUDA Installation Guide for Linux.
TorchLean needs nvcc, cuBLAS, and cuFFT. Check the machine before rebuilding:
nvidia-smi
nvcc --version
Build and run the CUDA configuration:
lake -R -K cuda=true build
lake -R -K cuda=true exe torchlean quickstart_mlp \
--device cuda --steps 10 --show-backend
The two CUDA choices happen at different times. -K cuda=true tells Lake to compile and link the
native CUDA implementation. --device cuda asks the executable to use it. A CPU-linked executable
rejects --device cuda instead of silently moving the run back to the CPU.
Use -R whenever you switch between CPU and CUDA configurations; it forces Lake to recompute the
build description. The CUDA regression suite is:
lake -R -K cuda=true exe nn_tests_suite
The CUDA guide covers deterministic reductions, parity checks, sanitizers, and the remaining native-code trust boundary.
Optional LibTorch Attention
The normal CPU and CUDA builds do not need LibTorch. TorchLean currently uses LibTorch only through an optional scaled-dot-product-attention bridge. Download a matching GPU-enabled distribution from the official LibTorch installation page and extract it somewhere outside the repository.
The extracted directory must contain include/ and lib/. Pass its absolute path to Lake:
lake -R -K cuda=true -K libtorch=true \
-K libtorch_home=/absolute/path/to/libtorch build
lake -R -K cuda=true -K libtorch=true \
-K libtorch_home=/absolute/path/to/libtorch exe libtorch_sdpa_test
This enables one registered external provider. It does not route every TorchLean operation through PyTorch, and it does not make LibTorch part of Lean’s trusted kernel.
macOS
Install Apple’s command-line developer tools, then Elan and TorchLean:
xcode-select --install
curl https://elan.lean-lang.org/elan-init.sh -sSf | sh
git clone https://github.com/lean-dojo/TorchLean.git
cd TorchLean
lake exe cache get
lake build
lake exe torchlean quickstart_mlp --device cpu --steps 10
The CPU path works on Intel and Apple silicon. Modern macOS has no NVIDIA CUDA execution path.
TorchLean already reserves --device metal in its device vocabulary, but Metal/MPS kernels are not
implemented yet. Selecting Metal therefore returns an unsupported-device error; it does not quietly
run the CPU implementation.
Windows
Recommended: WSL2
The most reliable Windows setup is Ubuntu under WSL2. Open an administrator PowerShell prompt:
wsl --install -d Ubuntu
After Windows restarts, open Ubuntu and follow the Linux instructions. For an NVIDIA GPU, follow NVIDIA’s CUDA on WSL guide. Install the Windows NVIDIA driver and the CUDA toolkit inside WSL; do not install a second Linux display driver inside WSL.
Native Windows
Native Windows is represented in the backend target vocabulary, but it is still a bring-up target rather than a regularly tested release path. Install Git, the Visual Studio C++ build tools, and the Windows SDK. Then install Elan from PowerShell:
curl -O --location https://elan.lean-lang.org/elan-init.ps1
powershell -ExecutionPolicy Bypass -f elan-init.ps1
del elan-init.ps1
The intended native CPU commands are:
lake exe cache get
lake build
The remaining work is platform engineering: the native libraries must be compiled with a compatible
Windows C/C++ toolchain; CUDA and LibTorch must be discovered as .lib and DLL artifacts; Linux
linker options such as -Wl,-rpath must be replaced; and the CPU stubs and GPU runtime must be tested
under the Windows loader and ABI. Once those pieces are wired, the existing device, provider, and
capsule abstractions do not need to be redesigned. Until then, WSL2 is the supported route for both
CPU and NVIDIA GPU execution on Windows.
Use TorchLean From Another Lean Project
Add TorchLean to the downstream project’s lakefile.lean:
require TorchLean from git "https://github.com/lean-dojo/TorchLean.git" @ "main"
Then update and build:
lake update
lake exe cache get
lake build
Most model files need only:
import NN
open TorchLean
For development against a neighboring checkout, use a path dependency:
require TorchLean from "../TorchLean"
From A Model To A Kernel
Installation ends once the project builds, but accelerated execution introduces one more question:
when a graph contains matmul, attention, or convolution, which implementation is allowed to run
it?
TorchLean separates three names:
- the device is where the work runs, such as CPU or CUDA;
- the provider is the implementation family, such as TorchLean, native CUDA, cuBLAS, cuFFT, or LibTorch;
- the operation is the mathematical work requested by the graph.
A device alone is not enough. Two CUDA providers may use different layouts, mask conventions, gradient implementations, or trust assumptions. TorchLean records those facts in a kernel capsule.
What A Kernel Capsule Looks Like
A capsule is a Lean record for one implementation of one operation. The native fused-attention
capsule is defined in NN.Backend.Attention; the essential fields look like this:
def nativeFlashAttention : KernelCapsule :=
{ name := "native_cuda.flash_attention"
op := .scaledDotProductAttention
provider := .nativeCuda
device := .cuda
specName := "Spec.flashAttention"
trustLevel := .checked
supportsForward := true
vjpMode := .backendVJP
shapeContract := ...
layoutContract := ...
valueContract := ...
vjpContract := ... }
Each contract field contains a structured claim rather than a free-form success label. For example, the layout field can state
{ claim := .layoutCompatibility .scaledDotProductAttention .flatRowMajor
summary := "Q, K, V, mask, and output use contiguous row-major buffers"
evidence := .runtimeGuard "Runtime.Autograd.Cuda.Tape.flashAttention" }
The claim says what must hold; the evidence says why the current profile is willing to use that implementation. A runtime guard or regression suite remains visible as a guard or test. It is not promoted to a theorem by placing it in the record.
The planner also checks that the shape, layout, value, and VJP fields contain the corresponding claim
for the capsule’s operation. A proof attached to the wrong field is rejected. For theorem and checker
evidence, the capsule author is still responsible for stating the exact Lean proposition represented
by the structured claim; specName is an audit label, not a theorem by itself.
The record answers questions that are otherwise easy to lose in runtime plumbing:
| Field | Question it answers |
|---|---|
op |
Which graph operation does this implementation claim to execute? |
provider, device |
Which runtime family and hardware target may select it? |
specName |
Which Lean-level meaning is it expected to refine? |
| shape and layout contracts | Which dimensions, memory order, mask convention, and payload assumptions are required? |
| value contract | What supports the forward-value claim? |
| VJP mode and contract | Who computes the local gradient, and what supports that claim? |
| runtime support | Is the path executable, test-only, planner-only, or not wired yet? |
| trust level | Is the evidence proof-backed, checked, fuzzed, or an external assumption? |
Capsules are declared in the source registry. They are not invented after a run to make its backend look acceptable. The planner selects an existing capsule whose device, provider, gradient mode, and trust level satisfy the requested profile. Missing or inadmissible capsules cause planning to fail.
Where The Theorems Enter
A capsule does not prove foreign code merely by containing the name of a theorem. The proof itself must be a Lean declaration whose proof term is checked by Lean’s kernel. The capsule records which evidence is meant to support each obligation, and the audit and gate layers make missing or external evidence visible.
FlashAttention gives a concrete example. TorchLean already proves a semantic equality between its fused attention specification and standard scaled dot-product attention:
#check Spec.flashAttention_eq_scaledDotProductAttention
#check Spec.flashAttentionBackward_eq_scaledDotProductAttentionBackward
Those are genuine Lean theorems about two Lean definitions. They justify replacing the standard
attention specification with the fused specification. They do not prove that a particular CUDA
binary implements either definition. The current native CUDA capsule therefore records runtime
guards, regression tests, source provenance, and trust level checked, not verified.
To move a native capsule to a stronger status, the work has to happen in this order:
- define the mathematical operation and its domain assumptions in Lean;
- state the runtime refinement claim, including shape, layout, Float32, and error assumptions;
- prove that claim, or build a replay checker with a soundness theorem;
- attach that theorem or checker to the capsule;
- keep any remaining FFI, compiler, driver, or hardware assumption explicit.
Proof and checker evidence carry their Lean proof terms. Source files, native symbols, runtime guards, regression suites, and fuzz runs are recorded separately. They remain useful audit information, but strict acceptance does not treat them as theorems.
Planning And Trust Policies
For each backend-visible graph operation, TorchLean follows the same sequence:
- Read the graph. Keep the operation, shape, payload, and proof-facing specification.
- Apply the profile. Restrict the device, providers, gradient ownership, and accepted trust levels.
- Select a capsule. Choose a compatible implementation already present in the registry.
- Audit and gate. Reject missing evidence or forbidden external boundaries.
- Admit, execute, and report. The eager runtime rejects non-eager capsules, consumes an accepted executable capsule, and prints it on first use when `--show-backend` is set.
An accepted kernel or graph plan carries a Lean proof that its selected policy gate returned
accepted. No-grad execution requests only a forward contract; training rejects a forward-only
capsule for differentiable operations. Random sources are non-differentiable and therefore do not
need a local VJP.
The maintained profiles currently have these meanings:
| Profile | Forward provider | Backward ownership | Current status |
|---|---|---|---|
checked_cpu |
Reference CPU runtime | TorchLean tape | Implemented |
checked_cuda |
Native CUDA, cuBLAS, cuFFT | TorchLean tape or named backend VJP | Implemented |
libtorch_forward_cuda |
Selected LibTorch forward capsules | TorchLean tape | Registered selectively; not a universal dispatcher |
libtorch_autograd_cuda |
Selected LibTorch capsules | External autograd | Explicit larger trust boundary |
future_* |
Metal, ROCm, WebGPU, XLA, Neuron, custom providers | Provider-specific | Extension targets, not implemented runtimes |
The default CUDA profile does not silently choose LibTorch. LibTorch SDPA remains testOnly until
its capsule is connected to eager multi-head attention. External providers must be enabled
explicitly and remain visible in the backend report.
The corresponding Lean definitions are in
NN.Backend.Capsule,
NN.Backend.Profile, and
NN.Backend.Gate.
Adding Another Platform
Metal, ROCm, WebGPU/WASM, TPU/XLA, Trainium/Neuron, custom chips, and caller-supplied accelerators all use the same extension points:
- add the device and provider vocabulary;
- detect build and runtime availability honestly;
- register capsules only for the operations the provider implements;
- connect the selected capsules to executable runtime dispatch;
- supply shape, layout, value, and VJP evidence at the right trust level;
- add platform CI and parity tests before calling the target supported.
Until those pieces exist, target selection fails. Asking for Metal or TPU must never become an unreported CPU run.
Check An Installation
These commands cover the normal CPU installation:
lake build
lake lint
lake exe nn_tests_suite
lake exe torchlean --help
lake exe verify --help
For CUDA, rebuild and run the suite with -R -K cuda=true.
For a complete account of Lean axioms, executable checkers, CUDA and FFI code, external artifact
producers, and floating-point assumptions, read
TRUST_BOUNDARIES.md.
References
- Elan: Lean toolchain manager.
- Lean reference: validating proofs.
- NVIDIA CUDA Installation Guide for Linux.
- NVIDIA CUDA on WSL User Guide.
- Installing LibTorch.
- George C. Necula, “Proof-Carrying Code”, POPL 1997. Kernel capsules borrow the discipline of carrying explicit evidence with executable code, but a current TorchLean capsule is a contract and provenance record, not a proof-carrying binary.