Zulip Chat Archive
Stream: mathlib4
Topic: Porting Algebra.Group.Ext
Riccardo Brasca (Dec 03 2022 at 11:44):
I am porting Algebra.Group.Ext
in #837 and I am stuck at the very beginning. The mathlib3 code is
import algebra.hom.group
universe u
@[ext, to_additive]
lemma monoid.ext {M : Type u} ⦃m₁ m₂ : monoid M⦄ (h_mul : m₁.mul = m₂.mul) : m₁ = m₂ :=
begin
have h₁ : (@monoid.to_mul_one_class _ m₁).one = (@monoid.to_mul_one_class _ m₂).one,
from congr_arg (@mul_one_class.one M) (mul_one_class.ext h_mul),
set f : @monoid_hom M M (@monoid.to_mul_one_class _ m₁) (@monoid.to_mul_one_class _ m₂) :=
{ to_fun := id, map_one' := h₁, map_mul' := λ x y, congr_fun (congr_fun h_mul x) y },
have hpow : m₁.npow = m₂.npow, by { ext n x, exact @monoid_hom.map_pow M M m₁ m₂ f x n },
unfreezingI { cases m₁, cases m₂ },
congr; assumption
end
The mathlib4 is
import Mathlib.Algebra.Hom.Group
universe u
@[ext, to_additive]
theorem Monoid.ext {M : Type u} ⦃m₁ m₂ : Monoid M⦄ (h_mul : m₁.mul = m₂.mul) : m₁ = m₂ := by
have h₁ : (@Monoid.toMulOneClass _ m₁).one = (@Monoid.toMulOneClass _ m₂).one :=
congr_arg (MulOneClass.one M) (MulOneClass.ext h_mul)
let f : @MonoidHom M M (@Monoid.toMulOneClass _ m₁) (@Monoid.toMulOneClass _ m₂) :=
{ toFun := id, map_one' := h₁, map_mul' := fun x y => congr_fun (congr_fun h_mul x) y }
have hpow : m₁.npow = m₂.npow := by
ext (n x)
exact @MonoidHom.map_pow M M m₁ m₂ f x n
cases m₁
cases m₂
congr <;> assumption
#align monoid.ext Monoid.ext
The first error is about @MulOneClass.one M
. Why there is no MulOneClass.one
? I can fix it with @One.one M
, but the mathlib3 way is better in my opinion.
Using @One.one M
is get an error at MulOneClass.ext h_mul
application type mismatch
congr_arg (@One.one M) (MulOneClass.ext ?m.404)
argument
MulOneClass.ext ?m.404
has type
?m.81 = ?m.82 : Prop
but is expected to have type
MulOneClass.toOne = MulOneClass.toOne : Prop
I don't understand exactly what's wrong here...
Eric Wieser (Dec 03 2022 at 11:50):
I think this is because of old_structure_cmd
Eric Wieser (Dec 03 2022 at 11:50):
Does fun (inst : MulOneClass M) => inst.one
work?
Riccardo Brasca (Dec 03 2022 at 11:53):
It moves the error later, so I guess it works... but it's really hard to read
Eric Wieser (Dec 03 2022 at 11:55):
The problem is that in Lean3/old structures mul_one_class.one
is a real field, but in Lean 4/new structures M.one
is actualy syntax for M.to_has_one.one
but only works when used as field notation
Eric Wieser (Dec 03 2022 at 11:56):
I think it would be a reasonable feature request to ask that MulOneClass.one
be syntax for the lambda function above.
Floris van Doorn (Dec 03 2022 at 11:58):
This seems like the easiest thing to work around. Note that if the expected type of the function is known (\..one)
will work.
Riccardo Brasca (Dec 03 2022 at 11:59):
OK, not it complains about
let f : @MonoidHom M M (@Monoid.toMulOneClass _ m₁) (@Monoid.toMulOneClass _ m₂) :=
{ toFun := id, map_one' := h₁, map_mul' := fun x y => congr_fun (congr_fun h_mul x) y }
with
synthesized type class instance is not definitionally equal to expression inferred by typing rules, synthesized
toMulOneClass
inferred
toMulOneClass
:rolling_eyes:
Floris van Doorn (Dec 03 2022 at 12:00):
The proof has to be different anyhow, since the shape of the structure is different because of the new bundling.
Riccardo Brasca (Dec 03 2022 at 12:10):
OK, I seems more complicated than I thought. I am closing my WIP PR (where I basically didn't do anything) to "free" the file to anyone else interested, since I don't have much time this weekend.
Richard Osborn (Dec 03 2022 at 23:00):
So is something like the following even possible to write in lean4?
import Mathlib.Algebra.Hom.Group
variable (M) (m₁ m₂ : Monoid M)
#check @MonoidHom M M (@Monoid.toMulOneClass M m₁) (@Monoid.toMulOneClass M m₂) -- M →* M : Type u_1
def f : @MonoidHom M M (@Monoid.toMulOneClass M m₁) (@Monoid.toMulOneClass M m₂) where
toFun := id
map_one' := sorry
map_mul' := sorry
Scott Morrison (Dec 04 2022 at 01:26):
I mean, it is impossible to fill in the sorries in any version of Lean, so I guess not?
Richard Osborn (Dec 04 2022 at 14:28):
So I had a crack at porting the file. I managed to fix the proof of Monoid.ext
and fix the proofs of injectivity, but was unable to fix the proofs for DivInvMonoid.ext
and Group.ext
. I've created a PR mathlib4#850, so if anyone has any insights, please feel free to work on it.
Richard Osborn (Dec 04 2022 at 14:29):
My main issue was that lean4 forgets that m₁
is a DivInvMonoid
when deconstructing the instance, so I don't have access to theorems that require a DivInvMonoid
instance.
Richard Osborn (Dec 04 2022 at 14:34):
I also couldn't figure out how to tell lean that the div
in DivInvMonoid
was the same as the hDiv
in div_eq_mul_inv
.
Richard Osborn (Dec 04 2022 at 22:00):
So I managed to fix the first issue with deconstructing a class by delaying it in the proof giving me access to theorems for DivInvMonoid
and Group
. I feel like the main issue preventing me from completing the proofs is that lean is converting (·*·)
and (·/·)
into an hMul
and hDiv
and I can't quite wrap my head around how to give lean the information to apply lemmas using (·*·)
and (·/·)
. I've pushed updated versions of the proofs. Hopefully, the finishing touches to them is fairly trivial.
Eric Wieser (Dec 05 2022 at 00:05):
Scott Morrison said:
I mean, it is impossible to fill in the sorries in any version of Lean, so I guess not?
I think this question was asked poorly; in the real context, there are hypotheses available that say the one
and mul
agree
Eric Wieser (Dec 05 2022 at 00:10):
I think the problem is the new-style classes interfering with
let f : @MonoidHom M M (@Monoid.toMulOneClass _ m₁) (@Monoid.toMulOneClass _ m₂) :=
{ toFun := id, map_one' := h₁, map_mul' := fun x y => congr_fun (congr_fun h_mul x) y }
In particular, this calls MonoidHom.mk
and OneHom.mk
, and seems to pass the wrong typeclass arguments into these
Eric Wieser (Dec 05 2022 at 00:14):
This works:
let f : @MonoidHom M M m₁.toMulOneClass m₂.toMulOneClass :=
@MonoidHom.mk _ _ (_) _ (@OneHom.mk _ _ (_) _ id h₁)
(fun x y => congr_fun (congr_fun h_mul x) y)
Eric Wieser (Dec 05 2022 at 00:14):
I'm very new to Lean4; what does (_)
mean compared to _
?
Eric Wieser (Dec 05 2022 at 00:16):
Also, this feels like a place where the opaqueness of inferInstance
is causing a problem (swapping m₁.toMulOneClass
for the suggested by letI := m₁ <;> infer_instance
fails)
Eric Wieser (Dec 05 2022 at 00:24):
I was able to copy across the mathlib3 proof
lemma div_inv_monoid.ext {M : Type*} ⦃m₁ m₂ : div_inv_monoid M⦄ (h_mul : m₁.mul = m₂.mul)
(h_inv : m₁.inv = m₂.inv) : m₁ = m₂ :=
begin
have h₁ : (@div_inv_monoid.to_monoid _ m₁).one = (@div_inv_monoid.to_monoid _ m₂).one,
from congr_arg (@monoid.one M) (monoid.ext h_mul),
set f : @monoid_hom M M (by letI := m₁; apply_instance) (by letI := m₂; apply_instance) :=
{ to_fun := id, map_one' := h₁, map_mul' := λ x y, congr_fun (congr_fun h_mul x) y },
have hpow : (@div_inv_monoid.to_monoid _ m₁).npow = (@div_inv_monoid.to_monoid _ m₂).npow :=
congr_arg (@monoid.npow M) (monoid.ext h_mul),
have hzpow : m₁.zpow = m₂.zpow,
{ ext m x,
exact @monoid_hom.map_zpow' M M m₁ m₂ f (congr_fun h_inv) x m },
have hdiv : m₁.div = m₂.div,
{ ext a b,
exact @map_div' M M _ m₁ m₂ _ f (congr_fun h_inv) a b },
unfreezingI { cases m₁, cases m₂ },
congr, exacts [h_mul, h₁, hpow, h_inv, hdiv, hzpow]
end
as
theorem DivInvMonoid.ext {M : Type _} ⦃m₁ m₂ : DivInvMonoid M⦄ (h_mul : m₁.mul = m₂.mul)
(h_inv : m₁.inv = m₂.inv) : m₁ = m₂ := by
have := Monoid.ext h_mul
have h₁ : m₁.one = m₂.one := congr_arg (·.one) this
let f : @MonoidHom M M m₁.toMulOneClass m₂.toMulOneClass :=
@MonoidHom.mk _ _ (_) _ (@OneHom.mk _ _ (_) _ id h₁)
(fun x y => congr_fun (congr_fun h_mul x) y)
have hpow : m₁.npow = m₂.npow := congr_arg (·.npow) (Monoid.ext h_mul)
have hzpow : m₁.zpow = m₂.zpow := by
ext (m x)
exact @MonoidHom.map_zpow' _ _ (_) _ f (congr_fun h_inv) x m
have hdiv : m₁.div = m₂.div := by
ext (a b)
exact @map_div' _ _ (_) (_) _
(@MonoidHom.monoidHomClass _ _ (_) _) f (congr_fun h_inv) a b
rcases m₁ with @⟨_, ⟨inv₁⟩, ⟨div₁⟩, _, zpow₁⟩
rcases m₂ with @⟨_, ⟨inv₂⟩, ⟨div₂⟩, _, zpow₂⟩
congr
Eric Wieser (Dec 05 2022 at 00:30):
It seems that @
and (_)
is ultimately the trick here
Eric Wieser (Dec 05 2022 at 00:30):
Maybe it would be best to restart from the mathport output for the other instances now that we know that?
Richard Osborn (Dec 05 2022 at 00:46):
Whatever ends up being the most readable/maintainable. The original mathport output is also in a block comment for Group.ext
. Now that you have the MonoidHom
working, it should be a similar proof. Are you planning on working on that one? I can probably figure it out, following this method.
I am still slightly concerned that (·*·)
and (·/·)
are hMuls
and hDivs
. And it seems as though Mul
and Div
don't extend the classes, which seems weird to me. I'm assuming there's a good reason.
Richard Osborn (Dec 05 2022 at 02:28):
Ok, I've fixed up all the proofs and have emulated the mathlib3 versions. Thank you for the help!
Btw, is the extra destructuring that is happening at the end of these proofs something that congr
should be able to figure out on its own?
Riccardo Brasca (Dec 05 2022 at 09:40):
Do you mind adding to the porting wiki what you had to do?
Richard Osborn (Dec 05 2022 at 13:42):
As far as I understand it, to create a MonoidHom
(or OneHom
) with ambiguous instances, you need to use the mk
constructor and then use (_)
to delay the TC inference on the input type (or more generally any type in the 'contravariant' position?).
Eric Wieser (Dec 05 2022 at 13:52):
It's not delaying it, it's disabling it entirely
Eric Wieser (Dec 05 2022 at 13:52):
It's forcing it to use unification instead of typeclass search
Eric Wieser (Dec 05 2022 at 13:53):
Lean3 did that automatically for {...}
notation
Last updated: Dec 20 2023 at 11:08 UTC