Zulip Chat Archive
Stream: mathlib4
Topic: to_additive for generated lemmas
Lukas Miaskiwskyi (Jan 30 2023 at 10:59):
In porting Data.Finset.Pointwise (!4#1911), an innocuous to_additive
attribute on the following theorem is throwing an error:
theorem coe_npow (s : Finset α) (n : ℕ) : ↑(s ^ n) = (s: Set α) ^ n := by
change ↑(npowRec n s) = (s: Set α) ^ n
induction' n with n ih
· rw [npowRec, pow_zero, coe_one]
· rw [npowRec, pow_succ, coe_mul, ih]
The error is
application type mismatch
@npowRec._eq_1 (Finset α) Finset.zero
argument has type
Zero (Finset α)
but function has type
∀ [inst : One (Finset α)] [inst_1 : Mul (Finset α)] (x : Finset α), npowRec 0 x = 1
set_option trace.to_additive true
indeed reveals that to_additive
generates a translation of the theorem that contains npowRec._eq_1
, despite npowRec
itself being marked with the to_additive
attribute. I imagine ideally we'd like to_additive
to also be inherited by the generated lemmas, right? Is this a bug? Could try to work out an #mwe if necessary.
Floris van Doorn (Jan 30 2023 at 11:01):
I'll investigate.
Floris van Doorn (Jan 30 2023 at 13:34):
This went deeper than I thought.
This has to do with the fact that Lean doesn't generate equation lemmas for definitions eagerly anymore. Instead, it generates them when used (at most once per file, I think). However, I just realized that even if we do generate the equation lemmas eagerly, Lean doesn't use them, and just generates a new one anyway.
Floris van Doorn (Jan 30 2023 at 13:35):
Example:
-- Test1.lean
import Lean
def foo := 1
open Lean Elab Meta Command
#eval liftCoreM <| MetaM.run' <| do
let nm := `foo
let d ← getEqnsFor? nm true
logInfo m!"{d}" -- some ([_private.Mathlib.Test1.0.foo._eq_1])
-- Test2.lean
import Mathlib.Test1
open Lean Elab Meta Command
#eval liftCoreM <| MetaM.run' <| do
let nm := `foo
let d ← getEqnsFor? nm true
logInfo m!"{d}" -- some ([_private.Mathlib.Test2.0.foo._eq_1])
Floris van Doorn (Jan 30 2023 at 13:38):
And rw
uses getEqnsFor?
to generate the equation lemmas. I'm confused that simp
doesn't have the same behavior: I thought that simp
uses the original equation lemma. Let me figure out if that is true. If so, maybe rw
can use the same behavior as simp
...
Floris van Doorn (Jan 30 2023 at 13:38):
Or maybe it's possible to add all eagerly generated equation lemmas (i.e. in the same file as the original declaration) to the environment extension eqnsExt
, so that they can be found again (that should also save of generating a bunch of equation lemmas many times).
Floris van Doorn (Jan 30 2023 at 13:39):
@Lukas Miaskiwskyi this is going to be a nontrivial to_additive
fix, or a core change. If you want to work-around this in the meantime: don't use rw
on a definition. Instead, use something like simp [npowRec]
or rw [npowRec_zero]
(if that exists)
Lukas Miaskiwskyi (Jan 30 2023 at 13:45):
Very interesting as far as I understand it, thank you for looking into it! That workaround sounds doable.
Floris van Doorn (Jan 30 2023 at 14:18):
Apparently the difference is that rw
uses getEqnsFor? declName (nonRec := true)
when rewriting with a definition, and simp
uses getEqnsFor?
with nonRec
set to false. For non-recursive definitions this does nothing, and simp instead uses a separate list of declarations that should be unfolded, and unfolds them using unfoldDefinition?
Floris van Doorn (Jan 30 2023 at 14:27):
So I guess we need to_additive
to generate the equation lemmas for the additive declarations on the fly (like rw
does for the multiplicative declaration).
Floris van Doorn (Jan 30 2023 at 14:27):
@Mario Carneiro if you have time: do you know if there is a reason for this distinction in the behaviors of rw
and simp
?
Jannis Limperg (Jan 30 2023 at 14:30):
These lazily generated equation lemmas also cause issues for Aesop. I'm not sure how much sense this makes, but maybe equation lemmas could be added to the environment as 'lazy constants' with a specific name and type, but without a proof, and then the proof is computed once the constant is actually used?
Jannis Limperg (Jan 30 2023 at 14:34):
Of course this would require substantial core changes, so probably not a near-term solution.
Jakob von Raumer (Jan 30 2023 at 16:11):
Is the laziness just for better performance here?
Mario Carneiro (Jan 30 2023 at 16:21):
The laziness is to avoid generating lots of useless and unused theorems in a programming project like lean core
Mario Carneiro (Jan 30 2023 at 16:22):
I think the most sensible way to control equation generation is with a set_option
, so that we can enable it in proofy parts and disable it in meta parts
Floris van Doorn (Jan 30 2023 at 16:45):
It would still require a change in getEqnsFor?
, because currently it will keep generating equation lemmas for foo
in every file, even if you generated an equation lemma for foo
when you defined it.
Floris van Doorn (Jan 30 2023 at 16:51):
@Lukas Miaskiwskyi the original problem can be solved in a similar way as we solve the lemmas that simp
generated, so I pushed a fix in !4#1948
Last updated: Dec 20 2023 at 11:08 UTC