perf: optimize string literal equality simprocs for kernel efficiency#12887
Merged
perf: optimize string literal equality simprocs for kernel efficiency#12887
Conversation
Collaborator
|
Reference manual CI status:
|
mathlib-nightly-testing bot
pushed a commit
to leanprover-community/batteries
that referenced
this pull request
Mar 11, 2026
mathlib-nightly-testing bot
pushed a commit
to leanprover-community/mathlib4-nightly-testing
that referenced
this pull request
Mar 11, 2026
|
Mathlib CI status (docs):
|
c0bde30 to
b251f89
Compare
Collaborator
Author
|
!radar |
|
Benchmark results for b251f89 against e804829 are in. There are no significant changes. @nomeata
Small changes (3🟥)
|
mathlib-nightly-testing bot
pushed a commit
to leanprover-community/batteries
that referenced
this pull request
Mar 12, 2026
mathlib-nightly-testing bot
pushed a commit
to leanprover-community/mathlib4-nightly-testing
that referenced
this pull request
Mar 12, 2026
|
Mathlib CI status (docs):
|
This PR optimizes the `String.reduceEq`, `String.reduceNe`, and `Sym.Simp` string equality simprocs to produce kernel-efficient proofs. Previously, these used `String.decEq` which forced the kernel to run UTF-8 encoding/decoding and byte array comparison, causing 86+ kernel unfoldings on short strings. The new approach uses `String.ofList_injective` combined with `congrArg (List.get?Internal · i)` at the first differing character position, reducing kernel work to O(first_diff_pos) list indexing plus a single character comparison. For equal strings, `eq_true rfl` avoids kernel evaluation entirely. The shared proof construction is in `Lean.Meta.mkStringLitNeProof`, used by both the standard simprocs and the `Sym.Simp` ground evaluator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This PR further optimizes the kernel cost of string literal inequality proofs: - When strings differ at a character position, use `List.get!Internal` instead of `List.get?Internal` to compare `Char` directly without the `Option` wrapper. - When one string is a prefix of the other, use `List.drop` with `List.cons_ne_nil` instead of indexing past the end. This avoids `decide` entirely since `cons_ne_nil` is a definitional proof. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This PR replaces the `decide` step in string inequality character comparison with `Char.toNat` projection followed by `Nat.ne_of_beq_eq_false rfl`. The kernel now evaluates `Nat.beq` on two concrete natural numbers instead of going through the `Decidable` instance for `Char` equality, reducing the max kernel unfolds from 12 to 6 for typical string inequality proofs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b251f89 to
005e81b
Compare
Collaborator
Author
|
!radar |
|
Benchmark results for 005e81b against 47b3be0 are in. There are no significant changes. @nomeata
Small changes (6🟥)
|
Collaborator
Author
|
!radar |
|
Benchmark results for aaaf1dc against 47b3be0 are in. There are no significant changes. @nomeata
Small changes (3🟥)
|
Collaborator
Author
|
!radar |
|
Benchmark results for 3064709 against 47b3be0 are in. There are no significant changes. @nomeata
Small changes (3🟥)
|
leanprover-bot
added a commit
to leanprover/reference-manual
that referenced
this pull request
Mar 14, 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.
This PR optimizes the
String.reduceEq,String.reduceNe, andSym.Simpstring equality simprocs to produce kernel-efficient proofs. Previously, these usedString.decEqwhich forced the kernel to run UTF-8 encoding/decoding and byte array comparison, causing 86+ kernel unfoldings on short strings.The new approach reduces string inequality to
List CharviaString.ofList_injective, then uses two strategies depending on the difference:Different characters at position
i: Projects toNatviacongrArg (fun l => (List.get!Internal l i).toNat), then usesNat.ne_of_beq_eq_false rfl. This avoidsDecidableinstances entirely — the kernel only evaluatesNat.beqon two concrete natural numbers.One string is a prefix of the other: Uses
congrArg (List.drop n ·)withList.cons_ne_nil, which is a definitional proof requiring nodecidestep at all.For equal strings,
eq_true rflavoids kernel evaluation entirely.The shared proof construction is in
Lean.Meta.mkStringLitNeProof(Lean/Meta/StringLitProof.lean), used by both the standard simprocs and theSym.Simpground evaluator.Kernel max unfolds for
"hello" ≠ "foo": 86+ → 6.