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.)
72 lines
1.3 KiB
Text
72 lines
1.3 KiB
Text
/-!
|
||
Checks that the simp cache is consulted within `simpLoop`, not just in `simpMain`
|
||
-/
|
||
|
||
|
||
axiom testSorry : α
|
||
opaque a : Nat
|
||
opaque b : Nat
|
||
opaque c : Nat
|
||
opaque f : Nat → Nat
|
||
opaque P : Nat → Prop
|
||
theorem ab : a = b := testSorry
|
||
theorem bc : b = c := testSorry
|
||
theorem ba : b = a := testSorry
|
||
theorem fafb : f a = f b := testSorry
|
||
|
||
set_option trace.Meta.Tactic.simp.rewrite true
|
||
|
||
|
||
-- This trace should only mention one `bc` rewrite, not two.
|
||
|
||
/--
|
||
trace: [Meta.Tactic.simp.rewrite] bc:1000:
|
||
b
|
||
==>
|
||
c
|
||
[Meta.Tactic.simp.rewrite] h:1000:
|
||
P c
|
||
==>
|
||
True
|
||
[Meta.Tactic.simp.rewrite] ab:1000:
|
||
a
|
||
==>
|
||
b
|
||
[Meta.Tactic.simp.rewrite] h:1000:
|
||
P c
|
||
==>
|
||
True
|
||
[Meta.Tactic.simp.rewrite] and_self:1000:
|
||
True ∧ True
|
||
==>
|
||
True
|
||
-/
|
||
#guard_msgs in
|
||
example (h : P c) : P b ∧ P a := by simp [ab, bc, h]
|
||
|
||
-- Almost the same goal, but ordered differently.
|
||
|
||
/--
|
||
trace: [Meta.Tactic.simp.rewrite] ab:1000:
|
||
a
|
||
==>
|
||
b
|
||
[Meta.Tactic.simp.rewrite] bc:1000:
|
||
b
|
||
==>
|
||
c
|
||
[Meta.Tactic.simp.rewrite] h:1000:
|
||
P c
|
||
==>
|
||
True
|
||
[Meta.Tactic.simp.rewrite] h:1000:
|
||
P c
|
||
==>
|
||
True
|
||
[Meta.Tactic.simp.rewrite] and_self:1000:
|
||
True ∧ True
|
||
==>
|
||
True
|
||
-/
|
||
#guard_msgs in
|
||
example (h : P c) : P a ∧ P b := by simp [ab, bc, h]
|