Repository navigation
verify: Export spec collections to Lean, and extend cppverify_auto for them - #65
Merged
Merged
Conversation
…the toolchain once.
…eft out, also when it comes first.
…ugh a rejected module.
… module that redeclares a name.
… in the architecture.
…the prelude on its own.
…they apply to Specs.
…hen a User lemma uses sorry.
… again only when what it imports changed.
…moved proof's imports.
…g_8d7035_division_by_zero_df06c970.lean.
…g_8d7035_missing_return_54ae7c80.lean.
…g_8d7035_postcondition_54ae7c80.lean.
…g_8d7035_precondition_155ffe95.lean.
…g_8d7035_precondition_814bc5b2.lean.
…_contract_eb6f5c_division_by_zero_d81a153d.lean.
…perations, and their lemmas.
…nfolding to cppverify_auto as revision 2.
…fs by hand to be the user's.
…eps in the design.
…y_auto in the architecture.
This was referenced Oct 24, 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.
Stacked on #62 (and #63 under it), whose commits show here until they merge; merge after #62.
The Lean backend refuses every function that uses a spec collection. On
main,--backend=leanon a file of a proof function over each kind:Now each is exported,
cppverify_autoproves its goals, and certification givesCertified.Design
Representation. Core Lean types, with Mathlib left opt-in as decided for 0.2:
<cppverify.h>seqList IntsetInt → Bool, its membership testmultisetInt → Nat, its countsmapInt → Option Int, the value at each key it holds<cppverify.h>may be infinite. Vermilion's mirror of vstd (read as data) uses Mathlib'sFinsetandMultiset, which fit vstd's finite sets but not ours.decideevaluates membership, counts, reads, and sequence equality at constants. Equality of sets, multisets, and maps is equality of functions.Operations. Each is a prelude function (
LeanCollectionPrelude):cppSeqEmpty,cppSeqUnit,cppSeqLength,cppSeqAt,cppSeqPush,cppSeqConcat,cppSeqSubrange,cppSeqContains,cppSet*,cppMultiset*,cppMap*. Each has the certifier's total semantics (Certify.cpp):S[From..To), withFrom = max 0 (min lo len)andTo = max From (min hi len);Natsubtraction.updateandreversestay specs over these, as for the solvers.Membership. The three membership predicates are
defs withDecidableinstances. A first version made themabbrevs, so that instance search would sees x = true. But thencppverify_norm's Boolean simp lemmas rewrotecppSetContains s xtos x = true, and no lemma stated oncppSetContainsmatched any more.Lemmas. As Vermilion states each vstd operation for its ladder, the prelude states each operation's meaning in
@[simp, grind =]lemmas, all proved in core Lean 4.35:cppSeqAt_push,_concat,_subrange,_unit;cppSeqLength_*;cppSeqContains_push,_concat,_unit;cppSeqSubrange_all,_push,_concat_left,_concat_right;cppSetContains_*,cppSetSubset_iff,cppMultisetCount_*,cppMapContains_*,cppMapGet_*;cppSeq_ext,cppSet_ext,cppMultiset_ext,cppMap_ext.Lengths and counts are not negative, stated through
grind_pattern. With a plain@[grind], grind took the normalized inequality-1 * count m x ≤ 0as the pattern, which no goal contains.Automation.
cppverify_autorevision 2 appends three steps after the five of revision 1, so that every goal an earlier step proves keeps its proof. They come from probing candidate steps on every collection goal of the suite:cppverify_auto_bveq: equalities of machine values, such asx != yfor two keys, and sign extensions become integer facts too (← BitVec.toInt_inj,toInt_signExtend_of_lewithomegafor its side condition);cppverify_auto_ext: a collection equality is proved by the kind's extensionality lemma;cppverify_auto_unfold: the definition instances a goal states are unfolded by the bodies they name (cppSpecBody_…). A body names only lower levels of its definition, so the unfolding ends. Tagging the bodies forgrindinstead would have changed every earlier step.A stub that revision 1 wrote is tried again, as LS1 designed for a new revision.
Measured over LS1's probe set (375 exported sources, 9259 goals), each ladder as
cppverify_autoruns it, with a step budget of its own:_bveqis not subsumed by_unfold. I ran each step alone on the 242 sources where revision 1 leaves a goal unproved. On 37 goals ofroundtrip_uleb128(llvm_uleb128.cpp), unfolding the lifted helpers' bodies exhausts the heartbeats, and_bveqproves them.Tests
suite/lean_collections.testexports a proof function over each kind and a recursive spec over a sequence and over a set. It checks:Specs.lean:List Int -> Intand(Int → Bool) -> Int -> Int;total(s.push(x)) == total(s) + xin place of its automatic one, and the false claimUnresolved;CertifyTest.AgreesWithLeanEvaluationgains collections:[1, 2, 3]forlo, hiin[-1, 4], reads at -1 and past the end, membership of an element inserted and removed, each combination of two sets, a multiset removal of a count of 0, 1, and 2, a key written over and removed.A first version had only the random chains, and printing set removal as insertion passed it.
lean_automation.test,lean_modules.test: revision 2 in the headers.lean_modules.test's goals overtriare now automatic, and a rerun after its proofs by hand counts them as the user's.lean_toolchain.test(verify: Try cppverify_auto on each new Lean goal, and certify it faster #61's) is unchanged.Docs
Checked
lean_collections.testamong them, and the docs tests pass. VerifyTests: 62 passed, 1 skipped;AgreesWithLeanEvaluationtakes 11 s.lean_fallback.test:fibo_stepis now certified with no proof by hand._unfoldproves its postcondition from the definition instances the goal states. The test's certification failure and its JSON case now usefibo_six, whose postcondition still needs a proof.check-doc-examples.pypasses on every page this changes (72 examples, 23 against the verdicts their pages show), the new checked export included._ext, no_bveq(killed by the check of the step that proves each goal), no_unfold; the revision not bumped;grind_patternfor counts; set membership as anabbrev; membership of a concatenation, or the subrange of a push, not stated as a lemma.main: every function ofInputs/lean_collections.cppisUnresolvedwithlogic.unsupported, as quoted above.