Commit graph

10131 commits

Author SHA1 Message Date
Henrik Böving
8435dea274
perf: fix two non linearities in the language server (#11915) 2026-01-14 09:54:21 +00:00
Leonardo de Moura
3dfd125337
feat: handle over/under-applied functions in Sym.simp (#11999)
This PR adds support for simplifying the arguments of over-applied and
under-applied function application terms in `Sym.simp`, completing the
implementation for all three congruence strategies (fixed prefix,
interlaced, and congruence theorems).
2026-01-14 01:40:42 +00:00
Joachim Breitner
c24df9e8d6
perf: faster T.ctor.injEq generation using substVars and some curry (#11998)
This improves upon #11992.
2026-01-13 23:02:18 +00:00
Eric Wieser
abed967ded
fix: add OfNat instance for LeanOptionValue (#11859)
This PR removes the need to write `.ofNat` for numeric options in
`lakefile.lean`. Note that `lake translate-config` incorrectly assumed
this was already legal in earlier revisions.

This replaces #11771.
2026-01-13 09:44:36 +00:00
Sebastian Ullrich
48a1b07516
perf: improve FromJson construction for big inductives (#11981)
We used to create a deeply nested syntax tree for checking each
constructor one by one, now we do a single big string literal match.
2026-01-13 08:49:43 +00:00
Leonardo de Moura
1cd6db1579
feat: auto-generated congruence theorems for Sym.simp (#11985)
This PR implements support for auto-generated congruence theorems in
`Sym.simp`, enabling simplification of functions with complex argument
dependencies such as proof arguments and `Decidable` instances.

Previously, `Sym.simp` used basic congruence lemmas (`congrArg`,
`congrFun`, `congrFun'`, `congr`) to construct proofs when simplifying
function arguments. This approach is efficient for simple cases but
cannot handle functions with dependent proof arguments or `Decidable`
instances that depend on earlier arguments.

The new `congrThm` function applies pre-generated congruence theorems
(similar to the main simplifier) to handle these complex cases.
2026-01-13 03:00:39 +00:00
Rob23oba
e2353689f2
fix: ensure linearity in floatLetIn (#11983)
This PR fixes the `floatLetIn` pass to not move variables in case it
could break linearity (owned variables being passed with RC 1). This
mostly improves the situation in the parser which previously had many
functions that were supposed to be linear in terms of `ParserState` but
the compiler made them non-linear. For an example of how this affected
parsers:
```lean-4
def optionalFn (p : ParserFn) : ParserFn := fun c s =>
  let iniSz  := s.stackSize
  let iniPos := s.pos
  let s      := p c s
  let s      := if s.hasError && s.pos == iniPos then s.restore iniSz iniPos else s
  s.mkNode nullKind iniSz
```
previously moved the `let iniSz := ...` declaration into the `hasError`
branch. However, this means that at the point of calling the inner
parser (`p c s`), the original state `s` needs to have RC>1 because it
is used later in the `hasError` branch, breaking linearity. This fix
prevents such moves, keeping `iniSz` before the `p c s` call.
2026-01-12 22:26:18 +00:00
Leonardo de Moura
e56351da7a
fix: pattern unification/matching in Sym (#11976)
This PR adds missing type checking for pattern variables during pattern
matching/unification to prevent incorrect matches.

Previously, the pattern matcher could incorrectly match expressions even
when pattern variable types were incompatible with the matched subterm
types. For example, a pattern like `x` where `x : BitVec 0` could match
any term, ignoring the specific type constraint on `x`.

This PR introduces a two-phase type checking approach:

1. **Static analysis** (`mkCheckTypeMask`): Identifies which pattern
variables require type checking based on their syntactic position.
Variables that appear only as arguments to function applications skip
checking (the application structure already constrains their types),
while variables in function position, binder contexts, or standalone
positions must be checked.

2. **Runtime validation**: During matching, when a pattern variable is
assigned, its type is checked against the matched subterm's type if
flagged by the mask. Checking uses `withReducible` to balance soundness
and performance.

The PR also adds helper functions for debugging (`Sym.mkMethods`,
`Sym.simpWith`, `Sym.simpGoal`) and fixes a minor issue where
`Theorem.rewrite` could return `.step` with identical expressions
instead of `.rfl`.Body:
2026-01-12 02:25:26 +00:00
Leonardo de Moura
58e599f2f9
perf: optimize congruence proof construction in Sym.simp (#11974)
This PR optimizes congruence proof construction in `Sym.simp` by
avoiding
`inferType` calls on expressions that are less likely to be cached.
Instead of
inferring types of expressions like `@HAdd.hAdd Nat Nat Nat instAdd 5`,
we infer
the type of the function prefix `@HAdd.hAdd Nat Nat Nat instAdd` and
traverse
the forall telescope.

The key insight is that function prefixes are more likely shared across
many call sites
(e.g., all `Nat` additions use the same `@HAdd.hAdd Nat Nat Nat
instAdd`), so they
benefit from `inferType` caching. 

Benchmark results show improvements on workloads with shared function
prefixes:
- `many_rewrites_5000`: 48.8ms → 43.1ms (-12%)
- `term_tree_5000`: 53.4ms → 30.5ms (-43%)
2026-01-11 23:00:19 +00:00
Henrik Böving
c91a2c63c2
perf: fast paths for forEachWhere Expr.isFVar (#11973)
Add a fast path for the pattern `forEachWhere Expr.isFVar` to avoid
setting up the expression
traversal etc.

Pattern initially noticed by @Rob23oba
2026-01-11 22:38:16 +00:00
Sebastian Ullrich
28a5e9f93c
chore: revert "fix: avoid panic in async elaboration for theorems with docstrings in where" (#11969)
Reverts leanprover/lean4#11896 as it is not a principled fix
2026-01-11 10:26:10 +00:00
Leonardo de Moura
470498cc06
chore: cleanup Sym.simp (#11968) 2026-01-11 04:11:31 +00:00
Leonardo de Moura
d57f71c1c0
perf: optimize kernel type-checking for have-telescope simplification in Sym.simp (#11967)
This PR implements a new strategy for simplifying `have`-telescopes in
`Sym.simp` that achieves linear kernel type-checking time instead of
quadratic.

## Problem

When simplifying deep `have`-telescopes, the previous approach using
`have_congr'` produced proofs that type-checked in quadratic time. The
simplifier itself was fast, but the kernel became the bottleneck for
large telescopes.

For example, at n=100:
- **Before**: simp = 2.4ms, kernel = **225ms**
- **After**: simp = 3.5ms, kernel = **10ms**

The quadratic behavior occurred because the kernel creates fresh free
variables for each binder when type-checking, destroying sharing and
producing O(n²) intermediate terms.

## Solution

We transform sequential `have`-telescopes into a parallel
beta-application form:

```
have x₁ := v₁; have x₂ := v₂[x₁]; b[x₁, x₂]
  ↓ (definitionally equal)
(fun x₁ x₂' => b[x₁, x₂' x₁]) v₁ (fun x₁ => v₂[x₁])
```

This parallel form leverages the efficient simplifier for lambdas in
`Sym.simp`. This form enables:
1. Independent simplification of each argument
2. Proof construction using standard congruence lemmas
3. Linear kernel type-checking time

The algorithm has three phases:
1. **`toBetaApp`**: Transform telescope → parallel beta-application
2. **`simpBetaApp`**: Simplify using `congr`/`congrArg`/`congrFun'` and
`simpLambda`
3. **`toHave`**: Convert back to `have` form

## Benchmark Results

### Benchmark 1: Chain with all variables used in body

| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 50 | 1.2ms | 32ms | 1.6ms | 4.4ms |
| 100 | 2.4ms | **225ms** | 3.5ms | **10ms** |
| 200 | 4.5ms | — | 8.4ms | 27ms |
| 500 | 11.7ms | — | 33.6ms | 128ms |

### Benchmark 3: Parallel declarations (simplified values)

| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 50 | 0.5ms | 24ms | 0.8ms | 1.8ms |
| 100 | 1.2ms | **169ms** | 1.8ms | **5.3ms** |
| 200 | 2.2ms | — | 3.9ms | 17ms |
| 500 | 5.9ms | — | 12.3ms | 93ms |

### Benchmark 5: Chain with single dependency

| n | Before (simp) | Before (kernel) | After (simp) | After (kernel) |
|---|---------------|-----------------|--------------|----------------|
| 100 | 1.6ms | 6.2ms | 1.8ms | 6.2ms |
| 200 | 2.8ms | 21.6ms | 4.4ms | 16.5ms |
| 500 | 7.3ms | **125ms** | 12.8ms | **72ms** |

Key observations:
- Kernel time is now **linear** in telescope depth (previously
quadratic)
- Simp time increases slightly due to the transformation overhead
- Total time (simp + kernel) is dramatically reduced for large
telescopes
- The improvement is most pronounced when the body depends on many
variables

## Trade-offs

- Proof sizes are larger (more congruence lemma applications)
- Simp time has ~1.5x overhead from the transformation
- For very small telescopes (n < 10), the overhead may not pay off

The optimization targets the critical path: kernel type-checking was the
bottleneck preventing scaling to realistic symbolic simulation
workloads.
2026-01-11 02:20:47 +00:00
Kim Morrison
9280a0ba9e
fix: avoid panic in async elaboration for theorems with docstrings in where (#11896)
This PR fixes a panic that occurred when a theorem had a docstring on an
auxiliary definition within a `where` clause.

Reproducer:
```lean
theorem foo : True := aux where /-- -/ aux := True.intro
```

The issue was that `asyncMayModify` used `.any` to check if a nested
declaration could have its extension state modified, which returned
`false` when the declaration wasn't yet in `asyncConsts`. Using `.all`
instead returns `true` for `none` (vacuously true), allowing
modification
of extension state for nested declarations that haven't been added to
`asyncConsts` yet.

Closes #11799

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 09:39:31 +00:00
Kim Morrison
e42262e397
fix: allow private proof-valued structure fields in library suggestions (#11962)
This PR fixes library suggestions to include private proof-valued
structure fields.

Private proof-valued structure fields (like `private size_keys' :
keys.size = values.size`) generate projections with `_private.*` mangled
names. These were being filtered out by `isDeniedPremise` because
`isInternalDetail` returns true for names starting with `_`.

The fix allows private names through by checking `!isPrivateName name`,
following the pattern from #11946. This enables `grind +suggestions` to
discover and use private proof-valued structure fields from the current
module.

Soon I would like to fix the semantics of `isInternalDetail`, as the
current behaviour is clearly wrong, but as there are many call sites, I
would like to get the behaviour of tactics correct first.

Also switches `currentFile` to use `wasOriginallyTheorem` instead of
matching on `.thmInfo`, which correctly identifies both theorems and
proof-valued projections.

🤖 Prepared with Claude Code

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-10 08:40:54 +00:00
Kim Morrison
5bb7f37645
feat: add first_par combinator for try? with grind +locals (#11949)
This PR adds a new `first_par` tactic combinator that runs multiple
tactics in parallel and returns the first successful result (cancelling
the others).

The `try?` tactic's `atomicSuggestions` step now uses `first_par` to try
three grind variants in parallel:
- `grind? +suggestions` - uses library suggestion engine  
- `grind? +locals` - unfolds local definitions from current file
- `grind? +locals +suggestions` - combines both

This leverages `TacticM.parFirst` which already provides the "first
success wins" parallel execution with cancellation.

### Depends on
- [x] depends on: #11946

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-09 21:09:41 +00:00
Sebastian Graf
15a719cb36
chore: extract shared match splitting impl from FunInd and mvcgen (#11953)
This was an indepedently viable refactoring proposed by Joachim. It
fixes a bug in `mvcgen` exposed by the now reverted #11696.
2026-01-09 15:53:26 +00:00
Sebastian Graf
22bef1c45a
chore: revert "feat: abstract metavariables when generalizing match motives (#8099)" (#11941)
This PR reverts #11696.

Reopens #8099.
2026-01-09 08:24:03 +00:00
Kim Morrison
7b1fb7ac9e
feat: add simp +locals to include local definitions (#11947)
This PR adds a `+locals` configuration option to the `simp`, `simp_all`,
and `dsimp` tactics that automatically adds all definitions from the
current file to unfold.

Example usage:
```lean
def foo (n : Nat) : Nat := n + 1

-- Without +locals, simp doesn't know about foo
example (n : Nat) : foo n = n + 1 := by simp  -- fails

-- With +locals, simp can unfold foo
example (n : Nat) : foo n = n + 1 := by simp +locals  -- succeeds
```

The implementation iterates over `env.constants.map₂` (which contains
constants defined in the current module) and adds definitions to unfold.
Instance definitions and internal details are filtered out.

**Note:** For local theorems, use `+suggestions` instead, which will
include relevant local theorems via the library suggestion engine.

🤖 Prepared with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-09 07:19:40 +00:00
Kim Morrison
cd632b033d
feat: add grind +locals to include local definitions (#11946)
This PR adds a `+locals` configuration option to the `grind` tactic that
automatically adds all definitions from the current file as e-match
theorems. This provides a convenient alternative to manually adding
`[local grind]` attributes to each definition. In the form `grind?
+locals`, it is also helpful for discovering which local declarations it
may be useful to add `[local grind]` attributes to.

Example usage:
```lean
def foo (n : Nat) : Nat := n + 1

-- Without +locals, grind doesn't know about foo
example (n : Nat) : foo n = n + 1 := by grind  -- fails

-- With +locals, grind can use the equation
example (n : Nat) : foo n = n + 1 := by grind +locals  -- succeeds
```

Instance definitions and internal details are filtered out.

🤖 Prepared with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-09 07:19:32 +00:00
Leonardo de Moura
d92cdae8e9
feat: simpForall and simpArrow in Sym.simp (#11950)
This PR implements `simpForall` and `simpArrow` in `Sym.simp`.
2026-01-09 06:20:04 +00:00
Sebastian Ullrich
ea7c740ad4
fix: ctor visibility in mutual public inductives (#11940)
This PR fixes module system visibiltity issues when trying to declare a
public inductive inside a mutual block.

Fixes #11115
2026-01-08 14:25:25 +00:00
Sebastian Ullrich
aa8fa47321
chore: attributes do not have to be tracked as public uses (#11939) 2026-01-08 13:39:10 +00:00
Henrik Böving
7e6365567f
refactor: preparatory change from structure to inductive on LCNF (#11934) 2026-01-08 09:56:41 +00:00
Sebastian Ullrich
1361d733a6
feat: re-integrate lean4checker as leanchecker (#11887)
This PR makes the external checker lean4checker available as the
existing `leanchecker` binary already known to elan, allowing for
out-of-the-box access to it.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 09:41:33 +00:00
Kim Morrison
0ad15fe982
refactor: add message log capture helpers for tactic evaluation (#11933)
This PR adds utility functions for managing the message log during
tactic
evaluation, and refactors existing code to use them.

**New helpers in `Lean.Elab.Tactic`:**
- `withSuppressedMessages`: executes an action while suppressing new
messages
- `withCapturedMessages`: executes an action and returns any new
messages
- `hasErrorMessages`: checks if a message list contains errors

**Refactored to use these helpers:**
- `LibrarySearch.tryDischarger`: now uses `withSuppressedMessages`
- `Try.evalAndSuggest`: now uses `withSuppressedMessages`
- `Try.evalAndSuggestWithBy`: now uses `withSuppressedMessages`

These helpers provide a standard pattern for tactic validation that
needs to
inspect error messages (e.g., filtering out suggestions that produce
errors).

🤖 Prepared with Claude Code

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 05:25:36 +00:00
Leonardo de Moura
531dbf0e1b
perf: mkFunExtFor (#11932)
This PR eliminates super-linear kernel type checking overhead when
simplifying lambda expressions. I improved the proof term produced by
`mkFunext`. This function is used in `Sym.simp` when simplifying lambda
expressions.

 ### Lambda benchmark: before vs after optimization

| Lambda | Before simp (ms) | After simp (ms) | Simp speedup | Before
kernel (ms) | After kernel (ms) | Kernel speedup | Before proof | After
proof | Proof reduction |

|--------|------------------|-----------------|--------------|--------------------|-------------------|----------------|--------------|-------------|-----------------|
| 10 | 0.269 | 0.208 | 1.29× | 0.521 | 0.390 | 1.34× | 583 | 498 | 1.17×
|
| 20 | 0.457 | 0.382 | 1.20× | 1.126 | 0.651 | 1.73× | 1323 | 918 |
1.44× |
| 30 | 0.747 | 0.536 | 1.39× | 1.733 | 0.789 | 2.20× | 2263 | 1338 |
1.69× |
| 40 | 0.819 | 0.697 | 1.18× | 2.696 | 1.065 | 2.53× | 3403 | 1758 |
1.94× |
| 50 | 1.035 | 0.901 | 1.15× | 3.918 | 1.304 | 3.01× | 4743 | 2178 |
2.18× |
| 100 | 2.351 | 1.823 | 1.29× | 20.073 | 2.927 | 6.86× | 14443 | 4278 |
3.38× |
| 150 | 3.920 | 2.873 | 1.36× | 60.266 | 5.290 | 11.39× | 29143 | 6378 |
4.57× |
| 200 | 5.869 | 3.819 | 1.54× | 148.681 | 6.903 | 21.54× | 48843 | 8478
| 5.76× |

We can now handle much larger lambda expressions. For example:

lambda_1000: 20.869250ms, kernel: 98.637875ms, proof_size=42078

This new approach will be implemented in `Meta.simp` in the future. Here
is the table with the `Meta.simp` numbers.

 ### Old `Meta.simp` lambda benchmark

| Lambda | Simp time (ms) | Kernel time (ms) | Proof size |
|--------|----------------|------------------|------------|
| 10  | 2.308 | 0.667 | 1273 |
| 20  | 5.739 | 1.817 | 3323 |
| 30  | 10.687 | 3.320 | 6173 |
| 40  | 17.607 | 6.326 | 9823 |
| 50  | 28.336 | 9.024 | 14273 |
| 100 | 137.878 | 34.344 | 48523 |
| 150 | 395.429 | 77.329 | 102773 |
| 200 | 866.097 | 143.020 | 177023 |
2026-01-08 04:28:58 +00:00
Kim Morrison
975a81cdb8
feat: filter out deprecated lemmas from suggestions in exact?/rw? (#11918)
This PR filters deprecated lemmas from `exact?` and `rw?` suggestions.

Previously, both tactics would suggest deprecated lemmas, which could be
confusing for users since using the suggestion would trigger a
deprecation warning.

Now, lemmas marked with `@[deprecated]` are filtered out in the
`addImport` functions that populate the discrimination trees used by
these tactics.

**Example (before this PR):**
```lean
import Mathlib.Logic.Basic

example (h : ∃ n : Nat, n > 0) : True := by
  choose (n : Nat) (hn : n > 0 + 0) using h
  guard_hyp hn : n > 0  -- `rw?` would suggest `Eq.rec_eq_cast` which is deprecated
```

Zulip discussion:
https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/deprecated.20lemma.20from.20rw.3F/near/554106870

🤖 Prepared with Claude Code

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 23:45:04 +00:00
Kim Morrison
f7de0c408f
fix: improve error message for initialize with missing Nonempty instance (#11919)
This PR improves the error message when `initialize` (or `opaque`) fails
to find an `Inhabited` or `Nonempty` instance.

**Before:**
```
failed to synthesize
  Inhabited Foo
```

**After:**
```
failed to synthesize 'Inhabited' or 'Nonempty' instance for
  Foo

If this type is defined using the 'structure' or 'inductive' command, you can try adding a 'deriving Nonempty' clause to it.
```

Prompted by
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/initialize.20structure.20with.20IO.2ERef/near/564936030

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 23:44:33 +00:00
Kim Morrison
b0ebfaa812
fix: ensure use of unsafeEIO is marked as unsafe (#11926)
This PR adds an `unsafe` modifier to an existing helper function user
`unsafeEIO`, and also leaves the function private.
2026-01-07 21:38:37 +00:00
Leonardo de Moura
ff87bcb8e5
feat: add option for simplifying have decls in two passes (#11923)
This PR adds a new option to the function `simpHaveTelescope` in which
the `have` telescope is simplified in two passes:

* In the first pass, only the values and the body are simplified.
* In the second pass, unused declarations are eliminated.

This new mode eliminates **superlinear** behavior in the benchmark
`simp_3.lean`. Note that the kernel type checker still **exhibits**
quadratic behavior in this example, because it **does not have support**
for expanding a `have`/`let` telescope in a single step.
2026-01-07 01:58:36 +00:00
Kim Morrison
a6ed0d640d
feat: add #guard_panic command and substring option for #guard_msgs (#11908)
This PR adds two features to the message testing commands:

## `#guard_panic` command

A new `#guard_panic` command that succeeds if the nested command
produces a panic message. Unlike `#guard_msgs`, it does not check the
exact message content, only that a panic occurred.

This is useful for testing commands that are expected to panic, where
the exact panic message text may be volatile. It is particularly useful
when minimizing a panic discovered "in the wild", while ensuring the
panic behaviour is preserved.

## `substring := true` option for `#guard_msgs`

Adds a `substring := true` option to `#guard_msgs` that checks if the
docstring appears as a substring of the output (after whitespace
normalization), rather than requiring an exact match. This is useful
when you only care about part of the message.

Example:
```lean
/-- Unknown identifier -/
#guard_msgs (substring := true) in
example : α := x
```

## Refactoring

Also refactors `runAndCollectMessages` as a shared helper function used
by both `#guard_msgs` and `#guard_panic`.

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 01:34:49 +00:00
Leonardo de Moura
8154453bb5
feat: simplify have blocks in Sym.simp (#11920)
This PR implements support for simplifying `have` telescopes in
`Sym.simp`.
2026-01-07 00:10:47 +00:00
Leonardo de Moura
c871f66cfa
refactor: have telescope support (#11914)
This PR factors out the `have`-telescope support used in `simp`, and
implements it using the `MonadSimp` interface. The goal is to
use this nice infrastructure for both `Meta.simp` and `Sym.simp`.
2026-01-06 19:20:25 +00:00
Leonardo de Moura
f6c8b8d974
perf: replaceS and instantiateRevBetaS (#11911)
This PR minimizes the number of expression allocations performed by
`replaceS` and `instantiateRevBetaS`.
2026-01-06 03:03:01 +00:00
Leonardo de Moura
175661b6c3
refactor: reorganize SymM and GrindM monad hierarchy (#11909)
This PR reorganizes the monad hierarchy for symbolic computation in
Lean.

## Motivation

We want a clean layering where:
1. A foundational monad (`SymM`) provides maximally shared terms and
structural/syntactic `isDefEq`
2. `GrindM` builds on this foundation, adding E-graphs, congruence
closure, and decision procedures
3. Symbolic execution / VCGen uses `GrindM` directly without introducing
a third monad

## Changes

The core symbolic computation layer still lives in `Lean.Meta.Sym`. This
monad (`SymM`) provides:
- Maximally shared terms with pointer-based equality
- Structural/syntactic `isDefEq` and matching (no reduction, predictable
cost)
- Monotonic local contexts (no `revert` or `clear`), enabling O(1)
metavariable validation
- Efficient `intro`, `apply`, and `simp` implementations

The name "Sym" reflects that this is infrastructure for symbolic
computation: symbolic simulation, verification condition generation, and
decision procedures.

### Updated hierarchy

```
Lean.Meta.Sym   -- SymM: shared terms, syntactic isDefEq, intro, apply, simp
Lean.Meta.Grind -- GrindM: E-graphs, congruence closure (extends SymM)
```

Symbolic execution is a usage pattern of `GrindM` operating on
`Grind.Goal`, not a separate monad. This keeps the API surface minimal:
users learn two monads, and VCGen is "how you use `GrindM`" (for users
that want to use `grind`) rather than a third abstraction to understand.
2026-01-06 01:12:07 +00:00
Leonardo de Moura
fd88637948
perf: add PersistentHashMap.findKeyD and PersistentHashSet.findD (#11907)
This PR implements `PersistentHashMap.findKeyD` and
`PersistentHashSet.findD`. The motivation is avoid two memory
allocations (`Prod.mk` and `Option.some`) when the collections contains
the key.
2026-01-05 20:04:49 +00:00
Leonardo de Moura
7376772cbd
perf: use update.*! at AlphaShareCommon (#11906)
This PR tries to minimize the number of expressions created at
`AlphaShareCommon`.
2026-01-05 19:11:01 +00:00
Kim Morrison
c358b0c734
feat: add guards for grind patterns for getElem?_eq_none theorems (#11761)
This PR adds some `grind_pattern` `guard` conditions to potentially
expensive theorems.
2026-01-05 08:55:02 +00:00
Kim Morrison
460b3c3e43
fix: grind propagates 0 * a = 0 for CommSemiring (#11881)
This PR fixes an issue where `grind` failed to prove `f ≠ 0` from `f * r
≠ 0` when using `Lean.Grind.CommSemiring`, but succeeded with
`Lean.Grind.Semiring`.

The `propagateMul` propagator handles `0 * a = 0` and `a * 0 = 0` rules
for semirings that don't have full ring support in grind. Previously,
`CommSemiring` was excluded because it uses a ring envelope for
normalization, but that approach doesn't propagate these equalities back
to the original terms. Now `CommSemiring` also uses `propagateMul`.

Reported as
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Grind.20failure.20for.20CommSemiring.2C.20not.20Semiring

🤖 Prepared with Claude Code

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 03:14:35 +00:00
Leonardo de Moura
82f60a7ff3
feat: pre and post may return "done" in Sym.simp (#11900)
This PR adds a `done` flag to the result returned by `Simproc`s in
`Sym.simp`.

The `done` flag controls whether simplification should continue after
the result:
- `done = false` (default): Continue with subsequent simplification
steps
- `done = true`: Stop processing, return this result as final

## Use cases for `done = true`

### In `pre` simprocs
Skip simplification of certain subterms entirely:
```
def skipLambdas : Simproc := fun e =>
  if e.isLambda then return .rfl (done := true)
  else return .rfl
```

### In `post` simprocs
Perform single-pass normalization without recursive simplification:
```
def singlePassNormalize : Simproc := fun e =>
  if let some (e', h) ← tryNormalize e then
    return .step e' h (done := true)
  else return .rfl
```
With `done = true`, the result `e'` won't be recursively simplified.
2026-01-05 02:10:06 +00:00
Leonardo de Moura
f1c903ca65
feat: simplify lambdas in Sym.simp (#11898)
This PR adds support for simplifying lambda expressions in `Sym.simp`.
It is much more efficient than standard simp for very large lambda
expressions with many binders. The key idea is to generate a custom
function extensionality theorem for the type of the lambda being
simplified.

This technique is compatible with the standard `simp` tactic, and will
be ported in a separate PR.

<img width="581" height="455" alt="image"
src="https://github.com/user-attachments/assets/5911dc6c-03f0-48ed-843b-b8cb4f67ee61"
/>

### `lambda` benchmark summary

| Lambda size | MetaM (ms) | SymM (ms) | Speedup |
|-------------|------------|-----------|---------|
| 50          | 22.7       | 0.74      | ~31×    |
| 100         | 120.5      | 1.75      | ~69×    |
| 150         | 359.6      | 2.90      | ~124×   |
| 200         | 809.5      | 4.51      | ~180×   |
2026-01-05 01:00:30 +00:00
Kim Morrison
35d8925c50
fix: avoid panic in TagDeclarationExtension.tag on partial elaboration (#11882)
This PR adds a guard to `TagDeclarationExtension.tag` to check if the
declaration name is anonymous and return early if so. This prevents a
panic that could occur when modifiers like `meta` or `noncomputable` are
used in combination with syntax errors.

Reproducer:
```lean
public meta section
def private
```

Previously this would panic with:
```
PANIC at Lean.EnvExtension.modifyState: called on `async` extension,
must set `asyncDecl` in that case
```

This follows the same pattern as the fix in #10131 for `addDocString`
and the existing guard in `markNotMeta`.

See
https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/panic.20on.20doc-string/near/566110399

🤖 Prepared with Claude Code

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 00:36:58 +00:00
Leonardo de Moura
9f404d8fbe
chore: remove leftover (#11895) 2026-01-04 21:42:13 +00:00
Sebastian Ullrich
81c93aeae8
perf: ensure withTraceNodeBefore message is created lazily (#11893) 2026-01-04 20:38:39 +00:00
Leonardo de Moura
cf36ac986d
perf: optimize simp congruence proofs (#11892)
This PR optimizes the construction on congruence proofs in `simp`.
It uses some of the ideas used in `Sym.simp`.
2026-01-04 19:37:21 +00:00
Leonardo de Moura
78c9a01bb2
feat: check Sym.simp thresholds (#11890)
This PR ensures that `Sym.simp` checks thresholds for maximum recursion
depth and maximum number of steps. It also invokes `checkSystem`.
Additionally, this PR simplifies the main loop. Assigned metavariables
and `zetaDelta` reduction are now handled by installing `pre`/`post`
methods.
2026-01-04 04:27:46 +00:00
Leonardo de Moura
a2cf78ac4a
perf: Sym.Simp.DiscrTree retrieval (#11889)
This PR improves the discrimination tree retrieval performance used by
`Sym.simp`.
2026-01-04 03:51:56 +00:00
Leonardo de Moura
bc72487aed
refactor: Sym.simp (#11888)
This PR refactors `Sym.simp` to make it more general and customizable.
It also moves the code
to its own subdirectory `Meta/Sym/Simp`.
2026-01-04 02:17:23 +00:00
Leonardo de Moura
b40dabdecd
feat: add discrimination tree retrieval for Sym (#11886)
This PR adds `getMatch` and `getMatchWithExtra` for retrieving patterns
from
discrimination trees in the symbolic simulation framework. 
The PR also adds uses `DiscrTree` to implement indexing in `Sym.simp`.
2026-01-03 20:28:07 +00:00