Repository navigation
verify: Try cppverify_auto on each new Lean goal, and certify it faster - #61
Merged
Merged
Conversation
SwayamInSync
force-pushed
the
fix/lean-automation
branch
from
October 23, 2026 03:27
64bb01c to
e71d7ed
Compare
… when that fails.
…t the Lean processes.
… it does not count.
… proved by cppverify_auto.
…, wherever Lean is installed.
SwayamInSync
force-pushed
the
fix/lean-automation
branch
from
October 23, 2026 09:10
e71d7ed to
20cb2fc
Compare
This was referenced Oct 23, 2026
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.
Every goal of a Lean project was a stub, each
Trueincluded, so a project of a few functions needed tens of proofs before it certified. Forlean_readable.cpp, 35 goals, allsorry. Now:33 of the 35 goals are proved at export, in 8 s;
poly's two are nonlinear, which core Lean does not decide (Mathlib'snlinarithor the nativebv_decidetier, both opt-in by the Lean plan's decisions).Design
As Vermilion, Why3, and Frama-C's WP do, automation runs once, when the goals are generated, and the user sees only what it leaves.
cppverify_auto(CppVerify/Auto.lean, written with every export fromLeanAutomation.h): a ladder of steps, each with a heartbeat budget of its own (cppverify.autoBudget, 50000) and rolled back when it fails, runs out of heartbeats, leaves goals, or proves the goal with an axiom outside Lean's foundations, as Vermilion'svrml_ladderdoes (rungs, budgets, runtime exceptions caught, a rung counts only when it closes the goal). Steps, cheapest first:grind; the heap step (eachheapStore*equation turned into the function it defines and substituted, then the machine normalization, thengrind); the machine step (comparisons, constants, and overflow predicates as integer facts, thengrind);decide;simp_all. Each first unfolds a goal still in its readable form, as one without binders is afterapply G.of_readable.sorryAx). Of the 5740 goals that Z3 proves:grindalone 66.9%, the machine step 77.4%, the heap step 85.6% (681 only it proves), all of them 90.2%; the order was chosen by simulating every order over the measured times (mean 319 ms per goal proved, 1.9 s per goal not). Two more parts were measured and left out: stating the range of everyBitVec.toIntterm proved nothing more (grindknows the ranges; 5127 against 5129 goals), and removingInt.bmodwith anomegadischarger proved 32 fewer goals (5129 against 5161) and made the heap step slower (535 ms against 311 ms on average). What remains is nonlinear arithmetic, specs that need induction, and quantified frames.automateLeanProject): every exported goal whose proof file is still the one cpp-verify wrote, and whose header names no attempt by the currentLeanAutomationRevision, is tried, with the pinned toolchain if it is installed. A goal it proves gets the step that proved it as its proof (pristine, like a stub); any other gets a stub whose header records the attempt (automation: cppverify_auto 1 did not prove it). It is tried again only when the revision changes, and never once edited.grindclaiming two false goals (unsafe_i128_negation,unsafe_i128_division) with terms the kernel rejected, and the ladder rejects a step whose proof uses the user's unfinished lemma (an@[grind]theorem proved bysorry), trying the next one.--lean-auto-timeout, 20 s), and the goals after one that exceeds it start again in a new process. The trial runsleanitself, with theLEAN_PATHoflake env, so a stopped process leaves no child, in--jobschunks.#cppverify_axiomscommand append each step and each theorem's axioms (or that the kernel rejected it) to a report file, flushed line by line.Autotoo, builds the proofs--jobsat once, and checks every goal in one environment: all proof modules imported together, and every project module's constants replayed together through the kernel into the environment of the toolchain modules they import. An automatic proof importsLean, and importing it once per goal took 161 s for 33 goals; now 8 s, and the whole certification 204 s → 12 s. A check reads only kernel constants, so proofs imported together cannot change each other's checks. When the import or replay fails (a proof file that declares a goal's name, a module the kernel rejects), each goal is checked on its own, exactly as before. An equation lemma Lean derives in each module that unfolds a definition is accepted when every copy is the same.ChildProcess.{h,cpp}: polling and stopping a process, moved from the cvc5 adapter, which now uses it, and the environment for a child.--no-lean-autowrites stubs only.Tests
suite/lean_automation.test: an export (an automatic proof and its header, a stub that records the attempt, a goal stopped at a 3 s limit with the goals after it still tried, the counts, JSONlean_automatic); certification of both; a rerun tries nothing; an edited proof is kept and may usecppverify_auto; a stub of no attempt (as before automation) and one of an earlier revision are tried; a step proving a goal with an unfinished@[grind]lemma does not count, and the next step proves it;--no-lean-auto; both options without a project are errors.lean_certify.cpp,lean_dependencies.test, andlean_readable.cpp's stub checks use--no-lean-auto, since they test proofs written over stubs;lean_certifier.testkeeps automation and matches the stub's line by pattern;lean_fallback_partial.test's complete export is nowCertified, its return check proved bycppverify_auto;lean_toolchain.testexports with--no-lean-auto, so that its certification run under a fake elan triescppverify_autofirst whether or not Lean is installed, and checks that the trial's build runs the pinned Lean too (macOS CI, which has no Lean, tried the goal there and Linux did not, so the log differed).Mutants, each rebuilt and run against
lean_automation.test,lean_certifier.test, andlean_fallback_partial.test: 10 of 13 killed.lean_certifier.test's theorem past the kernel).Three survive:
grinddo with_inhabitedExprDummyterms, which the ladder now rejects first in every case it reproduced.theorem fooproved byrfland bydecide: it keeps one), so the fast path falls back when they differ; the kernel replay would catch a mismatched goal anyway.Docs
--no-lean-auto,--lean-auto-timeout, automation in--lean-project, parallel builds in--lean-certifyand--jobs, the time limits.Checked
Rebased onto
mainat 213a367 (with #57). The one conflict, intooling.rst's paragraph on jobs, keeps #57's sentence on the work-bounded probe and this PR's on Lean processes. On that tree, an assertions build passes the 41 Verify tests that mention Lean, #57's included. Before that, rebased onto f861d01 (with #46 and #49) without conflicts, and checked onmainat 62af455:llvm_uleb128_decoder_exhaustive.cppexcluded (lit never runs it).lean_automation.testand the docs examples among them), and the 22 that use cvc5, whose process loop now usesChildProcess.main:lean_automation.testfails at its first step:mainrejects--lean-auto-timeout, and without it printsExported: lean obligation: nextand writes asorrystub for every goal.-W;docs_examples.testnow runs ch17's two Lean examples as Lean exports, in a project of their own ({dir}incppverify-example: flags), and checks their verdicts.