Zulip Chat Archive
Stream: general
Topic: dfinsupp/finsupp type class issue
Kevin Buzzard (Jun 02 2021 at 18:31):
The discussion about type class inference going on here
isn't really relevant to that stream. Here's what's going on:
import linear_algebra.dfinsupp
variables {ι : Type*} {R : Type*} {η : ι → Type*} {N : Type*}
variables [semiring R] [add_comm_monoid N] [module R N]
-- to see the traces uncomment this
--set_option trace.class_instances true
-- this fails
example : add_comm_monoid (Π₀ (i : ι), η i →₀ N) := by apply_instance -- fails
/-
Here's a part of the trace (click on "apply_instance"):
[class_instances] (0) ?x_0 : add_comm_monoid (Π₀ (i : ι), η i →₀ N) :=
@dfinsupp.add_comm_monoid ?x_38 ?x_39 ?x_40
failed is_def_eq
??
-/
local attribute [-instance]
finsupp.has_zero
finsupp.add_zero_class
finsupp.add_monoid
--set_option trace.class_instances true
noncomputable example : add_comm_monoid (Π₀ (i : ι), η i →₀ N) := by apply_instance -- works
/-
Part of the trace:
[class_instances] (0) ?x_0 : add_comm_monoid (Π₀ (i : ι), η i →₀ N) := @dfinsupp.add_comm_monoid ?x_38 ?x_39 ?x_40
[class_instances] caching instance for add_comm_monoid (Π₀ (i : ι), η i →₀ N)
@dfinsupp.add_comm_monoid ι (λ (i : ι), η i →₀ N) (λ (i : ι), @finsupp.add_comm_monoid (η i) N _inst_2)
-/
Kevin Buzzard (Jun 02 2021 at 19:54):
Now mathlib-free (and addition-free!):
class add_zero_class (M : Type) extends has_zero M.
variables {ι : Type} {N : Type} {η : ι → Type} (β : ι → Type)
structure dfinsupp [Π i, has_zero (β i)] : Type :=
(to_fun : Π i, β i)
instance dfinsupp.has_zero {ι : Type} {β : ι → Type} [Π (i : ι), has_zero (β i)] :
has_zero (dfinsupp (λ i, β i)) := ⟨⟨λ _, 0⟩⟩
instance dfinsupp.add_zero_class [Π i, add_zero_class (β i)] :
add_zero_class (dfinsupp (λ i, β i)) :=
{ zero := 0 }
structure finsupp (α : Type) (M : Type) [has_zero M] :=
(to_fun : α → M)
instance finsupp.has_zero (α : Type) (M : Type) [has_zero M] :
has_zero (finsupp α M) := ⟨⟨λ i, 0⟩⟩
instance finsupp.add_zero_class (α : Type) (M : Type) [add_zero_class M] :
add_zero_class (finsupp α M) :=
{ zero := 0 }
example [add_zero_class N] : add_zero_class (dfinsupp (λ (i : ι), finsupp (η i) N)) :=
by apply_instance -- fails
local attribute [-instance] finsupp.has_zero
-- now it works
example [add_zero_class N] : add_zero_class (dfinsupp (λ (i : ι), finsupp (η i) N)) :=
by apply_instance
What is mathlib doing wrong here?
Sebastien Gouezel (Jun 02 2021 at 19:58):
Can you also do the Lean 4 analogue? If it also fails in Lean 4, we could ask the devs if something can be done about it. And if it works, great!
Kevin Buzzard (Jun 02 2021 at 20:06):
Here's the Lean 3 trace. You can see failed is_def_eq
failing but then succeeding with a definitionally equal problem. I'll try it in Lean 4.
example [add_zero_class N] : add_zero_class (dfinsupp (λ (i : ι), finsupp (η i) N)) :=
by apply_instance -- fails
/-
[class_instances] (0) ?x_0 : add_zero_class
(@dfinsupp ι (λ (i : ι), @finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(λ (i : ι), @finsupp.has_zero (η i) N (@add_zero_class.to_has_zero N _inst_1))) := @dfinsupp.add_zero_class ?x_4 ?x_5 ?x_6
failed is_def_eq
-/
local attribute [-instance] finsupp.has_zero
-- now it works
example [add_zero_class N] : add_zero_class (dfinsupp (λ (i : ι), finsupp (η i) N)) :=
by apply_instance
/-
[class_instances] (0) ?x_0 : add_zero_class
(@dfinsupp ι (λ (i : ι), @finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(λ (i : ι),
@add_zero_class.to_has_zero (@finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(@finsupp.add_zero_class (η i) N _inst_1))) := @dfinsupp.add_zero_class ?x_4 ?x_5 ?x_6
[class_instances] caching instance for add_zero_class...
-/
example [add_zero_class N] : (@dfinsupp ι (λ (i : ι), @finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(λ (i : ι), @finsupp.has_zero (η i) N (@add_zero_class.to_has_zero N _inst_1))) =
(@dfinsupp ι (λ (i : ι), @finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(λ (i : ι),
@add_zero_class.to_has_zero (@finsupp (η i) N (@add_zero_class.to_has_zero N _inst_1))
(@finsupp.add_zero_class (η i) N _inst_1))) := rfl
Riccardo Brasca (Jun 02 2021 at 20:12):
Wow, thank you Kevin!! This looks deeper than I expected...
Sebastien Gouezel (Jun 02 2021 at 20:12):
The first trace you're showing is failing with @finsupp.add_zero_class
, while the second one succeeds but with @dfinsupp.add_zero_class
. I guess you wanted to tell us that the first one also fails with the dfinsupp
version?
Kevin Buzzard (Jun 02 2021 at 20:14):
oh that is probably a typo on my part (I copied the wrong thing, let me check). Update: yes, I copied the wrong line. I fixed it now.
Kevin Buzzard (Jun 02 2021 at 20:55):
I couldn't get it to work in Lean 4 either.
Riccardo Brasca (Jun 05 2021 at 10:50):
I don't have time today to think about it, but in #7818 something even stranger happened. I was proving
local attribute [-instance] finsupp.has_zero
/-- `finsupp.split` is an additive equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
@[simps]
def sigma_finsupp_add_equiv_dfinsupp [add_zero_class N] : ((Σ i, η i) →₀ N) ≃+ (Π₀ i, (η i →₀ N)) :=
{ to_fun := sigma_finsupp_equiv_dfinsupp,
inv_fun := sigma_finsupp_equiv_dfinsupp.symm,
map_add' := λ f g, by {ext, refl},
.. sigma_finsupp_equiv_dfinsupp }
that worked very well. Then @Eric Wieser suggested to have map_add'
as an isolated lemma, so I wanted to prove
local attribute [-instance] finsupp.has_zero
lemma sigma_finsupp_equiv_dfinsupp_add [add_zero_class N] (f g : (Σ i, η i) →₀ N) :
(sigma_finsupp_equiv_dfinsupp (f + g) : Π₀ i, (η i →₀ N)) = (sigma_finsupp_equiv_dfinsupp f) +
(sigma_finsupp_equiv_dfinsupp g) :=
/-- `finsupp.split` is an additive equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
@[simps]
def sigma_finsupp_add_equiv_dfinsupp [add_zero_class N] : ((Σ i, η i) →₀ N) ≃+ (Π₀ i, (η i →₀ N)) :=
{ to_fun := sigma_finsupp_equiv_dfinsupp,
inv_fun := sigma_finsupp_equiv_dfinsupp.symm,
map_add' := λ f g, by {ext, refl},
.. sigma_finsupp_equiv_dfinsupp }
The strange thing is that I get the failed to synthesize type class instance for
error about has_add (Π₀ (i : ι), η i →₀ N)
in sigma_finsupp_equiv_dfinsupp_add
, but still sigma_finsupp_add_equiv_dfinsupp
just below works.
Riccardo Brasca (Jun 05 2021 at 10:57):
A simpler example
local attribute [-instance] finsupp.has_zero
variables [add_zero_class N] (f g : (Σ i, η i) →₀ N)
example : has_add (Π₀ (i : ι), η i →₀ N) := by apply_instance -- works
#check (sigma_finsupp_equiv_dfinsupp f) --Π₀ (i : ι), η i →₀ N
#check (sigma_finsupp_equiv_dfinsupp f) + (sigma_finsupp_equiv_dfinsupp g) --fails
Eric Wieser (Jun 05 2021 at 11:01):
What if you add an explicit type ascription to the failing check? (Maybe to both operands)
Eric Wieser (Jun 05 2021 at 11:01):
I think sometimes that forces lean to redo a typeclass search
Riccardo Brasca (Jun 05 2021 at 11:06):
Ah, #check ((sigma_finsupp_equiv_dfinsupp f) + (sigma_finsupp_equiv_dfinsupp g) : (Π₀ (i : ι), η i →₀ N))
works!
Eric Wieser (Jun 05 2021 at 11:11):
I think I had to do this higher up in the file you're working in
Riccardo Brasca (Jun 05 2021 at 11:21):
But smul
is different
example [add_comm_monoid N] [module R N] : has_scalar R (Π₀ i, (η i →₀ N)) := by apply_instance --fails
example [add_comm_monoid N] [module R N] : has_scalar R (Π₀ i, (η i →₀ N)) := dfinsupp.has_scalar --OK
-- no problem here
/-- `finsupp.split` is a linear equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
@[simps]
def sigma_finsupp_lequiv_dfinsupp [add_comm_monoid N] [module R N] :
((Σ i, η i) →₀ N) ≃ₗ[R] (Π₀ i, (η i →₀ N)) :=
{ map_smul' := λ r f, by {ext, refl},
.. sigma_finsupp_add_equiv_dfinsupp }
Eric Wieser (Jun 05 2021 at 11:44):
I assume you run into trouble again if you try to declare a standalone smul lemma?
Riccardo Brasca (Jun 05 2021 at 11:52):
Yes, that's what I was trying to do
Eric Wieser (Jun 05 2021 at 12:01):
Your snippet above doesn't show that attempt
Riccardo Brasca (Jun 05 2021 at 12:05):
example [add_comm_monoid N] [module R N] : has_scalar R (Π₀ i, (η i →₀ N)) := by apply_instance --fails
example [add_comm_monoid N] [module R N] : has_scalar R (Π₀ i, (η i →₀ N)) := dfinsupp.has_scalar --OK
--this fails
@[simp]
lemma sigma_finsupp_equiv_dfinsupp_smul [add_comm_monoid N] [module R N] (r : R)
(f : (Σ i, η i) →₀ N) : sigma_finsupp_equiv_dfinsupp (r • f) =
r • (sigma_finsupp_equiv_dfinsupp f : (Π₀ (i : ι), η i →₀ N)) :=
by {ext, refl}
/-- `finsupp.split` is a linear equivalence between `(Σ i, η i) →₀ N` and `Π₀ i, (η i →₀ N)`. -/
@[simps]
def sigma_finsupp_lequiv_dfinsupp [add_comm_monoid N] [module R N] :
((Σ i, η i) →₀ N) ≃ₗ[R] (Π₀ i, (η i →₀ N)) :=
{ map_smul' := λ r f, by {ext, refl},
.. sigma_finsupp_add_equiv_dfinsupp }
In the add
lemma both examples worked :thinking:
Eric Wieser (Jun 05 2021 at 12:06):
What if you relax module to distrib_mul_action?
Eric Wieser (Jun 05 2021 at 12:07):
module
is only needed for the bundled map
Riccardo Brasca (Jun 05 2021 at 12:11):
This works
example [add_comm_monoid N] [module R N] : distrib_mul_action R (Π₀ i, (η i →₀ N)) := by apply_instance
Eric Wieser (Jun 05 2021 at 12:13):
I mean replace module R N
Eric Wieser (Jun 05 2021 at 12:13):
Since docs#dfinsupp.distrib_mul_action doesn't need it
Eric Wieser (Jun 05 2021 at 12:14):
Oh...
Eric Wieser (Jun 05 2021 at 12:14):
You need #7664 for that to work
Riccardo Brasca (Jun 05 2021 at 12:16):
Ah yes, that doesn't work but indeed the lemma is really missing
Eric Wieser (Jun 05 2021 at 12:19):
Does attribute [-instance] dfinsupp.distrib_mul_action dfinsupp.has_scalar
help?
Eric Wieser (Jun 05 2021 at 12:19):
To force it to find the module instance
Riccardo Brasca (Jun 05 2021 at 12:23):
Hmm...
example [add_comm_monoid N] [module R N] : module R (Π₀ i, (η i →₀ N)) := by apply_instance
works, even without local attribute [-instance] dfinsupp.distrib_mul_action dfinsupp.has_scalar
. But has_scalar
does not.
Riccardo Brasca (Jun 05 2021 at 12:24):
And has_scalar
doesn't work even with local attribute [-instance] dfinsupp.distrib_mul_action dfinsupp.has_scalar
.
Eric Wieser (Jun 05 2021 at 13:55):
This works:
@[simp]
lemma sigma_finsupp_equiv_dfinsupp_smul [add_comm_monoid N] [module R N] (r : R)
(f : (Σ i, η i) →₀ N) :
sigma_finsupp_equiv_dfinsupp (r • f) =
@has_scalar.smul R (Π₀ i, η i →₀ N) mul_action.to_has_scalar r (sigma_finsupp_equiv_dfinsupp f) :=
by { ext, refl }
Eric Wieser (Jun 05 2021 at 13:56):
Typeclass search shows that it while trying to satisfy finsupp.distrib_mul_action
it ends up rejecting module.to_distrib_mul_action
Eric Wieser (Jun 07 2021 at 17:04):
I think i'm seeing a similar issue to this one in #7834
Last updated: Dec 20 2023 at 11:08 UTC