Commit graph

3136 commits

Author SHA1 Message Date
Leonardo de Moura
62d2688579
feat: eta-reduction support in SymM (#12168)
This PR adds support for eta-reduction in `SymM`.
2026-01-26 21:30:29 +00:00
Joachim Breitner
a6a3df8af0
perf: use .inj in proof of .injEq (#12164)
This PR uses the `.inj` theorem in the proof of one direction of the
`.injEq` theorem.
2026-01-26 14:50:32 +00:00
Joachim Breitner
e94ed002b5
perf: in FunInd, boldly do not check terms (#12160)
This PR removes calls to `check` that we expect to pass under normal
circumstances. This may be re-added later guarded by a `debug` option.
2026-01-26 11:22:00 +00:00
Leonardo de Moura
0e28043ec6
feat: add simpTelescope simproc for simplifying binders before intro (#12154)
This PR adds `simpTelescope`, a simproc that simplifies telescope
binders (`have`-expression values and arrow hypotheses) but not the
final body. This is useful for simplifying targets before introducing
hypotheses.
2026-01-25 23:16:30 +00:00
Leonardo de Moura
45862d5486
feat: improves simpArrowTelescope simproc (#12153)
This PR improves the `simpArrowTelescope` simproc that simplifies
non-dependent arrow telescopes: `p₁ → p₂ → ... → q`.

The simproc now also applies telescope-specific simplifications:
- `False → q` to `True` (when `q : Prop`)
- `True → q` to `q` (when `q : Prop`)
- `p → True` to `True`
2026-01-25 22:29:38 +00:00
Leonardo de Moura
ba8c2ed4ee
feat: add simpArrowTelescope for compact proofs of arrow simplification (#12152)
This PR adds `simpArrowTelescope`, a simproc that simplifies telescopes
of non-dependent arrows (p₁ → p₂ → ... → q) while avoiding quadratic
proof growth.

When using `Expr.forallE` to represent nested implications, each nesting
level bumps de Bruijn indices in subterms, destroying sharing even with
hash-consing. For example, a free variable `x` gets different de Bruijn
representations at each depth, causing proof terms to grow.

`simpArrowTelescope` works by:

- Converting arrows to `Arrow p q` (a definitional wrapper)
- Simplifying each component
- Converting back to `→` form

Since `Arrow` arguments are not under binders, subterms remain identical
across nesting levels and can be shared.

The `simp_4` benchmark demonstrates the improvement:

With `forallE`: ~160ms, proof_size ≈ 173k
With `Arrow`: ~43ms, proof_size ≈ 16k
Tradeoff: `simpArrowTelescope` misses simplifications that depend on the
arrow structure (e.g., `p → p` to `True`), since post-methods aren't
applied to intermediate arrows. Thus, it is not used by default. to use
it, one has to set `simpArrowTelescope` as a `pre`-method.
2026-01-25 20:43:59 +00:00
Leonardo de Moura
e90f6f77db
test: local rewrite with Sym.simp (#12147)
This PR adds a new API for helping users write focused rewrites.
2026-01-25 01:32:50 +00:00
Leonardo de Moura
9deb9ab59d
refactor: move commonly shared expressions to SymM (#12145)
This PR moves the pre-shared commonly used expressions from `GrindM` to
`SymM`.
2026-01-25 00:17:53 +00:00
Leonardo de Moura
6de7100f69
feat: add Goal API for SymM + grind (#12143)
This PR adds an API for building symbolic simulation engines and
verification
condition generators that leverage `grind`. The API wraps `Sym`
operations to
work with `grind`'s `Goal` type, enabling lightweight symbolic execution
while
carrying `grind` state for discharge steps.

New operations on `Goal`:
- `mkGoal`: create a `Goal` from an `MVarId`
- `introN`, `intros`: introduce binders
- `apply`: apply backward rules
- `simp`, `simpIgnoringNoProgress`: simplify using `Sym.Simp`
- `internalize`, `internalizeAll`: add hypotheses to the E-graph
- `grind`: attempt to close the goal using `grind`
- `assumption`: close by matching a hypothesis

A new test demonstrates the API on a stateful program with conditionals,
using `grind` to discharge arithmetic side conditions.
2026-01-24 20:30:08 +00:00
Joachim Breitner
3bfeb0bc1f
refactor: use isRecursiveDefinition when validating macro_inline (#12106)
This PR uses `isRecursiveDefinition` when validating `macro_inline`,
instead of rummaging in the internals of the definition.
2026-01-22 16:31:34 +00:00
Leonardo de Moura
c81a8897a9
feat: improve Sym.simp APIs and new benchmark data (#12101)
This PR improves the the `Sym.simp` APIs. It is now easier to reuse the
simplifier cache between different simplification steps. We use the APIs
to improve the benchmark at #12100.

### Symbolic simulation with simplifier cache reuse (SymM)

Problem size `n` corresponds to a program with `2·n + 2` instructions.

| n   | Tactic time (ms) | Kernel time (ms) |
|-----|------------------|------------------|
| 10  | 4.53  | 4.29  |
| 20  | 5.56  | 6.91  |
| 30  | 6.46  | 8.67  |
| 40  | 8.07  | 11.20 |
| 50  | 9.37  | 13.63 |
| 60  | 11.89 | 15.43 |
| 70  | 12.43 | 18.28 |
| 80  | 14.07 | 20.72 |
| 90  | 15.62 | 23.41 |
| 100 | 17.39 | 24.80 |
| 200 | 30.35 | 48.39 |
| 300 | 45.41 | 72.84 |
| 400 | 59.17 | 97.67 |
| 500 | 79.63 | 138.99 |
| 600 | 100.05 | 173.67 |
| 700 | 119.77 | 208.80 |

<img width="571" height="455" alt="image"
src="https://github.com/user-attachments/assets/70da7ea2-b5d2-405e-985c-bfa358455afc"
/>
2026-01-22 03:37:16 +00:00
Leonardo de Moura
af438425d5
perf: avoid mkAppM in Sym.simp (#12099)
This PR ensures `Sym.simpGoal` does not use `mkAppM`. It also increases
the default number of maximum steps in `Sym.simp`.
2026-01-22 00:01:43 +00:00
Leonardo de Moura
f84aa23d6d
feat: metavar cleanup in Sym.simp (#12096)
This PR cleanups temporary metavariables generated when applying
rewriting rules in `Sym.simp`.
2026-01-21 21:36:17 +00:00
Leonardo de Moura
08e6f714ca
chore: normalize Sym APIs (#12088)
This PR cleanups the Sym APIs for `apply` and `simp`.
2026-01-21 17:02:22 +00:00
Leonardo de Moura
b8f8dde0b3
feat: checkMaxShared (#12083)
This PR adds the debugging helper functions `Expr.checkMaxShared` and
`MVarId.checkMaxShared` to `Sym`, and fixes a bug when visiting
telescopes in `Sym.simp`.
2026-01-21 14:55:46 +00:00
Leonardo de Moura
8258cfe2a1
fix: preprocessLCtx (#12081)
This PR fixes a bug in the `Sym.preprocessLCtx` function.
2026-01-21 14:05:43 +00:00
Leonardo de Moura
9063adbd51
feat: String and Char simprocs for SymM (#12077)
This PR implements simprocs for `String` and `Char`. It also ensures
reducible definitions are unfolded in `SymM`
2026-01-21 00:05:40 +00:00
Leonardo de Moura
e9a1c9ef63
feat: offset terms in Sym (#12053)
This PR adds support for offset terms in `SymM`. This is essential for
handling equational theorems for functions that pattern match on natural
numbers in `Sym.simp`. Without this, it cannot handle simple examples
such as

```lean
def pw (n : Nat) : Nat :=
  match n with
  | 0 => 1
  | n+1 => 2 * pw n

example : pw 4 = 16 := by
  sym_simp [pw.eq_1, pw.eq_2]

example : pw (a + 2) = 2 * (2 * pw a) := by
  sym_simp [pw.eq_2]
```
2026-01-20 04:57:52 +00:00
Leonardo de Moura
ea9c7cf2ae
feat: add simprocs for cond and dependent if-then-else in Sym.simp (#12040)
This PR adds simprocs for simplifying `cond` and dependent
`if-then-else` in `Sym.simp`.
2026-01-19 01:35:09 +00:00
Leonardo de Moura
c3726bdf05
feat: simplify match-expressions in Sym.simp (#12039)
This PR implements `match`-expression simplification for `Sym.simp`.
2026-01-19 00:37:22 +00:00
Leonardo de Moura
f63ddd67a2
feat: add simpControl simproc for if-then-else simplification (#12035)
This PR adds `simpControl`, a simproc that handles control-flow
expressions such as `if-then-else`. It simplifies conditions while
avoiding unnecessary work on branches that won't be taken.

The key behavior of `simpControl`:
- Simplifies the condition of `if-then-else` expressions
- If the condition reduces to `True` or `False`, returns the appropriate
branch, and continue simplifying.
- If the condition simplifies to a new expression, rebuilds the
`if-then-else` with the simplified condition (synthesizing a new
`Decidable` instance), and mark it as "done". That is, simplifier main
loop will not visit branches.
- Does **not** visit branches unless the condition becomes `True` or
`False`

This is useful for symbolic simplification where we want to avoid
wasting effort
simplifying branches that may be eliminated after the condition is
resolved.

This PR also fixes a bug in `Sym/Simp/EvalGround.lean`, and adds some
helper functions.
2026-01-18 04:14:26 +00:00
Leonardo de Moura
5457a227ba
feat: conditional rewriting in Sym.simp (#12033)
This PR adds support for conditional rewriting rules to `Sym.simp`.
2026-01-18 02:54:30 +00:00
Leonardo de Moura
de6ff061ed
feat: Sym.simp dischargers (#12032)
This PR adds `Discharger`s to `Sym.simp`, and ensures the cached results
are consistent.
2026-01-18 00:27:14 +00:00
Leonardo de Moura
6a87c0e530
feat: add Sym.Simp.evalGround simproc (#12031)
This PR adds `Sym.Simp.evalGround`, a simplification procedure for
evaluating ground terms of builtin numeric types. It is designed for
`Sym.simp`.

Key design differences from `Meta.Simp` simprocs:

- Pure value extraction: `getValue?` functions are `OptionT Id` rather
than
`MetaM`, avoiding `whnf` overhead since `Sym` maintains canonical forms
- Specialized predicate lemmas: comparisons use pre-proved lemmas like
  `Int.lt_eq_true` applied with `rfl`, avoiding `Decidable` instance
  reconstruction at each call site
- Type dispatch via `match_expr`: assumes standard instances, no
synthesis

Supported types: `Nat`, `Int`, `Rat`, `Fin n`, `BitVec n`,
`UInt8/16/32/64`,
`Int8/16/32/64`.

Supported operations: arithmetic (`+`, `-`, `*`, `/`, `%`, `^`), bitwise
(`&&&`, `|||`, `^^^`, `~~~`), shifts (`<<<`, `>>>`), comparisons (`<`,
`≤`,
`>`, `≥`, `=`, `≠`, `∣`), and boolean predicates (`==`, `!=`).
2026-01-17 05:13:12 +00:00
Leonardo de Moura
960c01fcae
feat: Sym.simp rewrite on over-applied terms (#12012)
This PR implements support for rewrite on over-applied terms in
`Sym.simp`. Example: rewriting `id f a` using `id_eq`.
2026-01-15 02:51:37 +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
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
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
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
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
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
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
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
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
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