lean4-htt/tests/lean/run/ack.lean
Joachim Breitner 2441bf1f76
perf: check simp cache in simpLoop (#8880)
This PR makes `simp` consult its own cache more often, to avoid
replicating work.

Before, the simp cache was checked upon entry of `simpImpl` only, which
then calls `simpLoop`, which recursively iterates the `pre`-lemmas,
without checking the cache again.

Now, `simpLoop` itself checks the cache. This seems more principled,
given that `simpLoop` is actually putting entries into the cache for
each of its calls, so it’s more uniform if it checks the cache itself.

This avoids repeated rewrites. For example given
```
theorem ab : a = b := testSorry
theorem bc : b = c := testSorry
example (h : P c) : P b ∧ P a := by simp [ab, bc, h]
```
simp would rewrite `b ==> c` twice (once as part of `b ==> c` and then
again as part of `a ==> b ==> c`). And it’d be order dependent: With
```
example (h : P c) : P a ∧ P b := by simp [ab, bc, h]
```
the `a ==> b ==> c` chain would insert `b ==> c` into the cache, and
picked up by `simpImpl` when rewriting `P b`.

With this change, `b ==> c` is performed only once in both examples.

Instruction counts on stdlib and mathlib both show a mild improvement
across the board (0.5%), with individual modules improving by up to 4%
in stdlib and even more in mathlib.


(This does not check the cache before applying `post`, which explains
where there are still some repeated rewrites in the trace logs. But I’m
less sure about inserting a cache check here and so I am treading
carefully here. It’s also going to be at most one `post` application
that’s duplicated, because if `post` returns `.visit`, we go back to
`pre` and thus a cache check.)
2025-06-21 17:58:05 +00:00

33 lines
1.1 KiB
Text

def ack : Nat → Nat → Nat
| 0, y => y+1
| x+1, 0 => ack x 1
| x+1, y+1 => ack x (ack (x+1) y)
termination_by a b => (a, b)
/--
trace: [diag] Diagnostics
[kernel] unfolded declarations (max: 147, num: 3):
[kernel] OfNat.ofNat ↦ 147
[kernel] Add.add ↦ 61
[kernel] HAdd.hAdd ↦ 61
use `set_option diagnostics.threshold <num>` to control threshold for reporting counters
---
trace: [simp] Diagnostics
[simp] used theorems (max: 57, num: 1):
[simp] ack.eq_3 ↦ 57
[simp] tried theorems (max: 57, num: 1):
[simp] ack.eq_3 ↦ 57, succeeded: 57
use `set_option diagnostics.threshold <num>` to control threshold for reporting counters
---
trace: [diag] Diagnostics
[kernel] unfolded declarations (max: 147, num: 3):
[kernel] OfNat.ofNat ↦ 147
[kernel] Add.add ↦ 61
[kernel] HAdd.hAdd ↦ 61
use `set_option diagnostics.threshold <num>` to control threshold for reporting counters
-/
#guard_msgs in
set_option diagnostics.threshold 50 in
set_option diagnostics true in
theorem ex : ack 3 2 = 29 :=
by simp [ack]