Repository navigation
feat(autograd): reduce the TapeM surface to one lemma, and prove it - #31
Merged
Merged
Conversation
NicolasRouquette
added a commit
to NicolasRouquette/TorchLean
that referenced
this pull request
Sep 5, 2026
Brings in the upstream PR branch (lean-dojo#31): TapeM.opM, the Proofs.Autograd.Builder family of run lemmas for all 31 tape-threading wrappers, and the rationals TapeBuilderTest that peels a do-block. Pure proof/test layer — no runtime, native or FFI surface is touched, so the CUDA work already on combined is unaffected.
Member
|
Hey Nicolas, can you rebase this onto the latest main? |
Member
|
Thanks! These TapeM proofs still look useful. Could you update this against current main and build around the existing |
Every op wrapper in `TapeM` is `TapeM.Internal.record` applied to its pure `Tape` counterpart. `NN/Proofs/Autograd/Tape/Builder.lean` proves how a successful, failing, and inverted `run` of `Internal.record op` relate to `op`, how a successful run of `m >>= f` splits into its stages, and states `TapeM.leaf`'s unconditional run. The `run_<op>_ok` family instantiates the first lemma at each of the 33 tape-threading wrappers with no unfolding lemma in between, so it cannot drift from what the wrappers do. `NN/Tests/Runtime/Rationals/TapeBuilderTest.lean` runs a user-style eager program over `ℚ`, checks its value, and proves from "the block ran" the pure-`Tape` fact behind each statement.
NicolasRouquette
force-pushed
the
tapem-run-lemmas
branch
from
October 3, 2026 19:21
15af007 to
465fe10
Compare
Contributor
Author
|
Rebased onto current What changed in the port:
Checks on The PR description is updated to match. |
NicolasRouquette
added a commit
to NicolasRouquette/TorchLean
that referenced
this pull request
Oct 3, 2026
Brings in the upstream PR branch (lean-dojo#31) at 465fe10, rebased onto upstream main b062b9a: TapeM.opM, the Proofs.Autograd.Tape.Builder family of run lemmas for the tape-threading wrappers, and the rationals TapeBuilderTest that peels a do-block. Pure proof/test layer; no runtime, native or FFI surface is touched.
Member
|
Hey Nicolas, thanks for this! The proof bridge compiles locally, the core lemma axiom checks contain only the standard Lean axioms, and the rational tape-builder example passes. Merging this one. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap
The pure tape engine (
Runtime.Autograd.Tape) is well covered by proofs.TapeM, theStateT (Tape α) Resultwrapper that users actually write eager programs in, has none underNN/Proofs/. So ado-block has no route back to a statement about the tape it built, and aproof about a program has to be written against a hand-threaded
Tape.<op>chain that is notthe program.
The observation this rests on
Every
TapeMwrapper that threads the tape isTapeM.Internal.recordapplied to its purecounterpart:
There are 33 of these, differing only in the pure op and its binders. So the whole surface
reduces through one lemma about
Internal.record, and nothing inTapeM.leanneeds to change.What the PR adds
NN/Proofs/Autograd/Tape/Builder.lean(new) proves, generic in the carrierα:record_run_ok/record_run_error: a pure op's outcome becomes the monadicrun'soutcome. The pair swaps: a pure op returns tape-then-id,
runreturns value-then-state.record_run_inv: and back again.run_bind_inv: a successfulrunofm >>= fsplits into its two successful stages. Thisis what peels a
do-block one statement at a time.run_leaf: stated separately, becauseleafis total; its pure counterpart returns a barepair rather than a
Result. On currentmainit isrfl.run_<op>_okfor all 33 tape-threading wrappers:add,sub,mul,div,scale,abs,sqrt,clamp,max,min,relu,linear,matmul,conv,convTranspose,maxPool,smoothMaxPool,avgPool,layerNorm,batchNorm,attention,mseLoss,sigmoid,tanh,softmaxLast,softplus,exp,sin,cos,log,inv,safeLog,sum.Each member of the family is the proof term
record_run_okwithopsupplied and nothingelse:
That is the property worth having: if one of these ever stops typechecking, its wrapper has
stopped being
Internal.recordat its pure op. The family cannot drift into stating somethingweaker than the wrapper does, because it is not stating anything separately. The binders are
copied from each wrapper, so every lemma can be applied exactly where its wrapper can be called.
TapeM.backwardScalaris deliberately outside the family: it reads the tape without writingone back, so it is a different shape.
Axiom profile
Checked with
#print axiomson465fe109: every lemma in the file,run_bind_invandrun_leafincluded, reports[propext, Classical.choice, Quot.sound], which is exactly whatRuntime.Autograd.TapeM.Internal.recordand theTapeops themselves report on this tree. Thelayer introduces nothing the runtime definitions it reasons about do not already carry.
The test does both things to one program
NN/Tests/Runtime/Rationals/TapeBuilderTest.leantakes a user-style block overℚ,runs it and checks the value (
4 * ([2,3] * [5,7])is[40, 84]), and proves, from nothingbut "the block ran", the pure-
Tapefact behind each of its four statements:The proof is the peel and nothing else:
run_bind_invonce per statement, thenrun_leaforrecord_run_invat each op.Tape.emptyhas no native implementation available to the elaborator, so the numeric halfcannot be forced by a compile-time
#guard; it runs undernn_tests_suite.Checks run
PR checklist
TapeBuilderTest, wired intoTests.Runtime.Rationals.Suite.sorryinNN/.