Zulip Chat Archive

Stream: nightly-testing

Topic: lean-pr-testing-4595


Kim Morrison (Jul 02 2024 at 00:51):

Is one of the authors of Mathlib.Tactic.ToAdditive, @Mario Carneiro, @Yury G. Kudryashov, @Floris van Doorn, @Jon Eugster available to help understand a failure of @[to_additive] on the lean-pr-testing-4595 branch?

(This is an experimental branch changing the proofs that simp generates when using dsimp lemmas, attempting to reduce the occurrence of "unguided" defeq problems in the kernel after simp.)

I am seeing failures in Mathlib.Data.Part, and in Mathlib.RingTheory.OreLocalization, where the @[to_additive] attribute is failing, and I'm not sure why.

Typical errors are:

@[to_additive "A difference is equal to its expansion by a summand from `S`."]
protected theorem expand' (r : X) (s s' : S) : r /ₒ s = s'  r /ₒ (s' * s) :=
  OreLocalization.expand r s s' (by norm_cast; apply SetLike.coe_mem)

producing

application type mismatch
  @Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7 R (AddSubmonoid R) AddZeroClass.toAdd
argument has type
  Add R
but function has type
   [inst : Mul R] [inst_1 : SetLike (AddSubmonoid R) R] [hA : MulMemClass (AddSubmonoid R) R] (S' : AddSubmonoid R)
    (x y : S'), x * y = (x * y)

and

@[to_additive]
theorem some_mul_some [Mul α] (a b : α) : some a * some b = some (a * b) := by simp [mul_def]

producing

application type mismatch
  mul_def
argument has type
  Add α
but function has type
   [inst : Mul α] (a b : Part α),
    a * b = do
      let y  a
      map (fun x  y * x) b

Note this is not a complete failure of @[to_additive], it is working fine still in basic files.

Floris van Doorn (Jul 02 2024 at 08:28):

See #10830. The issue is that simp generates subterms that don't have enough context to translate. They are lambda-terms quantifying over multiplicative type-classes, but applied to terms. We need to know what the terms are to decide whether we should translate these multiplicative type-classes (currently we do translate them).
Possible solutions:

  • adapt simp to not generate applied lambda-terms
  • adapt to_additive to beta-reduce the value before translating anything (this might actually be pretty feasible - but we also need to look at generated auxiliary declarations, which will be harder)
  • adapt to_additive to be more context-aware during the translation (probably not feasible).
  • Live with the status quo: the workaround is to specify the type explicitly in a few simp-rules.

Kim Morrison (Jul 02 2024 at 09:36):

@Floris van Doorn, could you explain what the workaround would look like here? Which simp rules do I need to look at to fix

@[to_additive]
theorem some_mul_some [Mul α] (a b : α) : some a * some b = some (a * b) := by simp [mul_def]

What type needs to be specified explicitly?

Floris van Doorn (Jul 02 2024 at 10:35):

This has nothing to do with #10830. It is fixed by adding @[to_additive] to Part.mul_def.

Floris van Doorn (Jul 02 2024 at 10:36):

I don't know why those lemmas don't have that...

Floris van Doorn (Jul 02 2024 at 10:37):

I pushed to the branch fixing Data.Part.

Floris van Doorn (Jul 02 2024 at 10:38):

We just didn't see it on master, since simp [mul_def] created a proof term that doesn't mention mul_def.

Floris van Doorn (Jul 02 2024 at 10:49):

Do you know the internals of simp?
Given a new declaration (to which we want to add the to_additive attribute) it would be very helpful to know which declarations were automatically generated by this declaration. to_additive needs to (potentially) additivize these declarations as well.
The current heuristic when adding declaration foo it will consider the following declarations that (may) have been added to the environment when elaborating foo:

  1. It has to occur in foo (or in a declaration automatically generated by foo)
  2. It has to be of one of these forms

Floris van Doorn (Jul 02 2024 at 11:46):

(ran off to lunch, now I'm back)
The first error in OreLocalization.Basic is a case where simp generates Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7, and to_additive currently doesn't consider additivizing this.

Kim Morrison (Jul 02 2024 at 11:47):

Why is that?

Kim Morrison (Jul 02 2024 at 11:47):

Surely this occurs everywhere?

Kim Morrison (Jul 02 2024 at 11:47):

It wasn't created during expand' (at least according to whatsnew in)

Kim Morrison (Jul 02 2024 at 11:48):

but presumably that just means that someone had previously used it as simp lemma.

Kim Morrison (Jul 02 2024 at 11:49):

Oh, when you said "one of these forms": Mathlib.MyFile._auxLemma.<something> did you literally mean that MyFile had to match the current file?

Floris van Doorn (Jul 02 2024 at 11:50):

Yes

Floris van Doorn (Jul 02 2024 at 11:52):

I don't recall why we did it this way. We could try to additivize everything that satisfies docs#Lean.Name.isInternalDetail.

Floris van Doorn (Jul 02 2024 at 11:52):

I think the reason is that there is a problem if files B and C both import file A, and both separately additivize A.something, then you now have two additive translations.

Kim Morrison (Jul 02 2024 at 11:53):

Ah -- at least for theorems this is allowed now.

Floris van Doorn (Jul 02 2024 at 11:53):

How does simp deal with this? Can it be the case that two files both generate Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7?

Kim Morrison (Jul 02 2024 at 11:53):

Yes, and we arrange that lean doesn't complain about the duplication in these cases!

Kim Morrison (Jul 02 2024 at 11:53):

So hopefully to_additive could take advantage of the same.

Floris van Doorn (Jul 02 2024 at 11:54):

So simp guarantees that all generated declarations with the name Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7 have exactly the same type?

Kim Morrison (Jul 02 2024 at 11:54):

That is a good question. I'm not confident there.

Kim Morrison (Jul 02 2024 at 11:54):

But presumably the answer is yes??

Floris van Doorn (Jul 02 2024 at 11:55):

Then I'm a bit surprised what the 7 indicates... It somehow must encode for what declaration it is generating an equation lemma.

Floris van Doorn (Jul 02 2024 at 11:57):

Kim Morrison said:

Surely this occurs everywhere?

to_additive calls docs#Lean.Meta.getEqnsFor? with nonrec := true on all declarations it additivizes. This ensures that most equation lemmas are already generated (and correctly additivized). This is a hack that maybe we can get rid of now...

Floris van Doorn (Jul 02 2024 at 11:59):

Though I'm still not sure if nonrec := false is the correct default for Mathlib. I expect that for most declarations we will use the equational lemmas multiple times, so it is cheaper to just always compute it once, instead of computing it potentially multiple times. (I can imagine that in other contexts this is the right default behavior.)

Floris van Doorn (Jul 02 2024 at 12:07):

I believe

Floris van Doorn said:

This is a hack that maybe we can get rid of now...

Probably we cannot (easily). A comment in the source code mentions

/- We need to generate all equation lemmas for `src` and `tgt`, even for non-recursive
definitions. If we don't do that, the equation lemma for `src` might be generated later
when doing a `rw`, but it won't be generated for `tgt`. -/

Kim Morrison (Jul 02 2024 at 12:10):

Ooh, so I made a hacky change so it will additivize everything, even from different files.

Kim Morrison (Jul 02 2024 at 12:10):

OreLocalization then succeeds.

Kim Morrison (Jul 02 2024 at 12:10):

I'll see if the rest of mathlib survives.

Floris van Doorn (Jul 02 2024 at 12:11):

I expect that in some random file you will get a clash of additivized names. But let's see.

Kim Morrison (Jul 02 2024 at 12:19):

Somewhat unexpectedly the first error is

error: ././././Mathlib/Algebra/BigOperators/Group/Finset.lean:1712:2: application type mismatch
  @one_ne_zero α inst✝² inst✝¹
argument has type
  Zero α
but function has type
   [inst : One α] [inst_1 : NeZero 1], 1  0

Shouldn't it already know not to touch this?

Floris van Doorn (Jul 02 2024 at 12:19):

The big issues of simp(/rw) + to_additive interactions that I currently see:

  1. If large lambda-terms are generated (that abstract over multiplicative classes), we should beta-reduce these beta-redexes before translation.
  2. We should correctly additivize generated auxiliary declarations (and manage if they come from different modules)
  3. If we generate an auxiliary declaration that cannot be additivized (maybe for a lemma about Ring) then we should have a mechanism that decides not to additivize it.

I believe the workaround of specifying types explicitly (mentioned in #10830) can work around both issues 1 and 3.
There are probably other issues I'm not seeing at the moment, though.

Kim Morrison (Jul 02 2024 at 12:20):

This is on branch#to_additive_all if you want to take a look.

Floris van Doorn (Jul 02 2024 at 12:20):

Well, one_ne_zero doesn't have a to_additive tag, but depending on your implementation you now basically made it have one?

Kim Morrison (Jul 02 2024 at 12:21):

I think I only changed anything about _auxLemma.

Kim Morrison (Jul 02 2024 at 12:21):

diff

Kim Morrison (Jul 02 2024 at 12:22):

Oh

Kim Morrison (Jul 02 2024 at 12:23):

I see, but as soon as someone uses it manually in simp...

Floris van Doorn (Jul 02 2024 at 12:23):

Not sure why you get that error on Master. But it is completely expected that to_additive translates One α to Zero α

Kim Morrison (Jul 02 2024 at 12:24):

Hrmm... is the additive version of OreLocalization even a useful thing? I would be just as happy here to rip out all the to_additives in this file!

Matthew Ballard (Jul 02 2024 at 12:25):

Algebraic K0K_0 was mentioned by Johan

Kim Morrison (Jul 02 2024 at 12:29):

Hmm, my hack breaks master pretty thoroughly. :-(

Floris van Doorn (Jul 02 2024 at 12:38):

Actually, I don't even know when and why Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7 is generated. It looks like the symmetric version of docs#MulMemClass.coe_mul (and not an equational lemma for docs#MulMemClass.mul ). Is that changing in lean4#4595 ?

Kim Morrison (Jul 02 2024 at 12:41):

lean#4595 is a pretty big change. It actually rewrites by all simp lemmas, even if they are rfl lemmas (previously we just omitted the proof, and this gave the kernel lots of hard defeq problems).

Kim Morrison (Jul 02 2024 at 12:42):

So yes, we are generating many more auxiliary lemmas (for all the rfl lemmas that we ever rewrite by).

Floris van Doorn (Jul 02 2024 at 12:44):

Can we generate them the moment that a declaration is tagged simp? (or when a definition is declared)?

Floris van Doorn (Jul 02 2024 at 12:45):

Though I guess when a definition is declared we already do that in to_additive.

Floris van Doorn (Jul 02 2024 at 12:47):

Or if we already do... Is there a way to figure out what the name is?

Floris van Doorn (Jul 02 2024 at 12:49):

Note: there is another hack in to_additive to figure out what lemmas are generated by simp. I expect this hack doesn't survive this change.
If this information is somehow available in the environment after the simp attribute is executed, that would make the behavior of to_additive less hacky, and we might then be able to find (and generate) the newly generated simp-lemmas.

Floris van Doorn (Jul 02 2024 at 12:52):

See docs#Lean.Meta.Simp.addSimpAttrFromSyntax (which is in Mathlib, despite its name)

Floris van Doorn (Jul 02 2024 at 13:00):

Looking at the pr-branch.
Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7 is generated the moment that MulMemClass.coe_mul is declared, but not currently caught and additivized by the current implementation of to_additive (probably because of the very hacky Lean.Meta.Simp.addSimpAttrFromSyntax)

Floris van Doorn (Jul 02 2024 at 13:00):

I have to run now.

Floris van Doorn (Jul 09 2024 at 13:04):

I'm investigating this a bit further. These declarations are generated by norm_cast. The attribute @[to_additive (attr := norm_cast)] applies the norm_cast attribute to both the multiplicative and additive declaration, creating the lemmas Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.7 and Mathlib.Algebra.Group.Subsemigroup.Operations._auxLemma.8. What is missing is that these lemmas should be put in the "multiplicative -> additive" dictionary that to_additive is using.
This is currently done in a very hacky way for the simp and simps attributes specifically, but not for other attributes.
I'm not sure what the best way forward is.
From the perspective of to_additive, it would be nice if every attribute could report "I generated this list of declarations" (in order).
I could try to extend the hack further to norm_cast, but maybe other attributes are also affected.
I could try something else hacky but more general, by comparing the environment before and after executing the command, and collecting the new attributes that way (but then I lose the order in which the declarations were added...)

Kim Morrison (Jul 09 2024 at 14:10):

Thanks Floris. My suggestoin would be to try extending the hack further to norm_cast for now. Given that we seem to get a fair way into Mathlib before this problem occurs, perhaps we can hope to get lucky.

Kim Morrison (Jul 09 2024 at 14:11):

Testing out the consequences of #4595 is moderately high priority: if this is something that we can make work we'd really like to.

Floris van Doorn (Jul 10 2024 at 09:43):

I think I will have time for this today.

Michael Rothgang (Jul 10 2024 at 11:56):

Kim Morrison said:

Testing out the consequences of #4595 is moderately high priority: if this is something that we can make work we'd really like to.

lean4#4595, right?

Floris van Doorn (Jul 10 2024 at 17:26):

This was a bit more painful since norm_cast is in Core now, but on branch#to-additive-4595 this issue is now fixed by increasing the hack. RingTheory.OreLocalization builds now.

Floris van Doorn (Jul 10 2024 at 17:36):

@Kim Morrison would Core be open to decreasing the depth of the hack?
This requires three things:

  • have Lean.Meta.addSimpTheorem return an array of declaration names that were generated. Two implementation options are on Mathlib master and on this branch (these are not equivalent, since on master we return the empty array if no declaration was generated, and on the branch we return #[declName], but both work well for me).
  • all declarations that use addSimpTheorem (currently, AFAIK: simp and norm_cast) and are used in attributes should also return an Array Name
  • The add field of the attributes should be separated out as definitions that also return an Array Name.
  • An alternative 3rd thing is that the add field docs#Lean.AttributeImpl have return type Lean.AttrM A for some configurable A and that for simp and norm_cast we have A := Array Name, but that might be too invasive.

Kyle Miller (Jul 10 2024 at 17:38):

What's the feasibility of avoiding working with _auxLemmas by unfolding them? (And perhaps using an Expr.beta to fold in the arguments?)

Floris van Doorn (Jul 10 2024 at 17:39):

Another alternative is that we store in the environment all simp lemmas associated to a declaration (separately, somewhere), and that to_additive has access to that.

Floris van Doorn (Jul 10 2024 at 17:40):

Kyle Miller said:

What's the feasibility of avoiding working with _auxLemmas by unfolding them? (And perhaps using an Expr.beta to fold in the arguments?)

Unclear: some proofs generated by simp that do not use declarations are actually hard to translate, as described in #10830. But maybe both of them can be solved by beta-reducing more.

Floris van Doorn (Jul 10 2024 at 17:41):

oh wait, that's not the right issue

Floris van Doorn (Jul 10 2024 at 17:43):

maybe #10830 is also solved by your suggestion... So it's probably worth looking into...

Floris van Doorn (Jul 10 2024 at 17:50):

branch#to-additive-4595 builds successfully. Feel free to force-push it into lean-pr-testing-4595 (that will remove your last commit).

Floris van Doorn (Jul 10 2024 at 17:51):

oh, unsuccesfully, but significantly more

Floris van Doorn (Jul 10 2024 at 17:54):

And it looks like the remaining failures have nothing to do with to_additive.

Floris van Doorn (Jul 10 2024 at 18:34):

Kyle Miller said:

What's the feasibility of avoiding working with _auxLemmas by unfolding them? (And perhaps using an Expr.beta to fold in the arguments?)

testing on branch#fvd/to_additive_unfold_aux . It seems to work quite well.

Floris van Doorn (Jul 10 2024 at 19:57):

It works! #14628


Last updated: May 02 2025 at 03:31 UTC