Zulip Chat Archive
Stream: Is there code for X?
Topic: Combine coproducts
Christian Merten (Nov 10 2023 at 21:53):
Is there something like this:
import Mathlib
open CategoryTheory Limits Functor
variable {C : Type u} [Category.{v, u} C]
def comb (α : Type*) (f : α → Type*) (g : (a : α) → f a → C)
(t : ∀ a, ColimitCocone (Discrete.functor (g a)))
(s : ColimitCocone (Discrete.functor (fun a ↦ (t a).cocone.pt))) :
Cocone (Discrete.functor (Sigma.uncurry g : Sigma f → C)) := sorry
i.e. given a family of coproduct diagrams indexed over some type α
and a coproduct of the cone points, is there one big coproduct on Sigma f
?
I tried to formulate this for arbitrary functors first (indead of restricting to Discrete.functor
) but I struggled to emulate the dependence on the value of f
.
There is docs#CategoryTheory.Limits.combineCocones but there the index categories are the same for every diagram (i.e. f
above would have to be constant).
Joël Riou (Nov 10 2023 at 22:32):
I prove something similar in PR #8242:
https://github.com/leanprover-community/mathlib4/pull/8242/files#diff-872c679954b062c45a489c6ba4184c58b3220532467f779d8859dcc80692358dR435-R444
Christian Merten (Feb 08 2024 at 11:53):
@Joël Riou To clean up some code, I tried to replace my ad-hoc proof of the sorry above by using the GradedObject
API, in particular I tried to use docs#CategoryTheory.GradedObject.isColimitCofanMapObjComp that you added in the above mentioned PR.
This is the very much horrible result:
import Mathlib
variable {C : Type} [Category C]
def blaequiv1 (ι : Type) (X : ι → C) :
Discrete ((fun x : ι ↦ ())⁻¹' {()}) ≌ Discrete ι := sorry
def blaequiv2 (ι : Type) (X : ι → C) :
((blaequiv1 ι X).functor ⋙ Discrete.functor X)
≅
Discrete.functor (X ∘ Subtype.val) := sorry
def blaequiv3 (ι : Type) (X : ι → C) :
GradedObject.CofanMapObjFun X (fun _ ↦ ()) ()
≌ Cofan X := by
symm
apply Cocones.equivalenceOfReindexing (blaequiv1 ι X) (blaequiv2 ι X)
def fooequiv1 (ι : Type) (t : ι → Type)
(f : (i : ι) → (a : t i) → C) (i : ι) :
Discrete ((fun x : Sigma t ↦ x.fst)⁻¹' {i}) ≌ Discrete (t i) := sorry
def fooequiv2 (ι : Type) (t : ι → Type)
(f : (i : ι) → (a : t i) → C) (i : ι) :
((fooequiv1 ι t f i).functor ⋙ Discrete.functor (f i))
≅ Discrete.functor (Sigma.uncurry f ∘ Subtype.val) :=
sorry
def fooequiv3 (ι : Type) (t : ι → Type)
(f : (i : ι) → (a : t i) → C) (i : ι) :
GradedObject.CofanMapObjFun (Sigma.uncurry f) Sigma.fst i
≌ Cofan (f i) := by
symm
apply Cocones.equivalenceOfReindexing (fooequiv1 ι t f i) (fooequiv2 ι t f i)
def combCofans (ι : Type) (t : ι → Type)
(f : (i : ι) → (a : t i) → C)
(cf : (i : ι) → Cofan (f i))
(cg : Cofan (fun i ↦ (cf i).pt)) :
Cofan (Sigma.uncurry f) := by
let I : Type := Sigma t
let X : GradedObject I C := Sigma.uncurry f
let J : Type := ι
let K : Type := Unit
let p : I → J := fun ⟨i, _⟩ ↦ i
let q : J → K := fun _ ↦ ()
let r : I → K := q ∘ p
have hpqr (i : I) : q (p i) = r i := rfl
let k : K := ()
let c (j : J) (_ : q j = k) : GradedObject.CofanMapObjFun X p j :=
(fooequiv3 ι t f j).inverse.obj (cf j)
let c' : Cofan (fun j : (q⁻¹' {k}) ↦ (c j rfl).pt) :=
(blaequiv3 J (fun j ↦ (c j rfl).pt)).inverse.obj cg
let cfm := X.cofanMapObjComp p q r hpqr k c c'
exact (blaequiv3 _ X).functor.obj cfm
def combCofansIsColimit (ι : Type) (t : ι → Type)
(f : (i : ι) → (a : t i) → C)
(cf : (i : ι) → Cofan (f i))
(hcf : (i : ι) → IsColimit (cf i))
(cg : Cofan (fun i ↦ (cf i).pt))
(hcg : IsColimit cg) : IsColimit (combCofans ι t f cf cg) := by
let I : Type := Sigma t
let X : GradedObject I C := Sigma.uncurry f
let J : Type := ι
let K : Type := Unit
let p : I → J := fun ⟨i, _⟩ ↦ i
let q : J → K := fun _ ↦ ()
let r : I → K := q ∘ p
have hpqr (i : I) : q (p i) = r i := rfl
let k : K := ()
let c (j : J) (_ : q j = k) : GradedObject.CofanMapObjFun X p j :=
(fooequiv3 ι t f j).inverse.obj (cf j)
let c' : Cofan (fun j : (q⁻¹' {k}) ↦ (c j rfl).pt) :=
(blaequiv3 J (fun j ↦ (c j rfl).pt)).inverse.obj cg
let cfm := X.cofanMapObjComp p q r hpqr k c c'
have : IsColimit cfm := by
apply GradedObject.isColimitCofanMapObjComp
· intro j h
show IsColimit (c j h)
apply (IsColimit.ofCoconeEquiv (fooequiv3 ι t f j).symm).symm (hcf j)
· show IsColimit ((blaequiv3 J (fun j ↦ (c j rfl).pt)).inverse.obj cg)
apply (IsColimit.ofCoconeEquiv (blaequiv3 J (fun j ↦ (c j rfl).pt)).symm).symm hcg
exact (IsColimit.ofCoconeEquiv (blaequiv3 _ X)).symm this
Christian Merten (Feb 08 2024 at 11:55):
I made it extra verbose to see what's going on. Do you think this can be optimized (more on a global scale, of course this can be golfed)? Or should I simply go with a direct implementation (which is not hard and definitely shorter than the above (even if one golfs away all the verboseness).
Joël Riou (Feb 08 2024 at 13:26):
If I had to do this, I think would first prove the following variant of GradedObject.isColimitCofanMapObjComp
, and then deduce the case of sigma types:
variable {I J C : Type*} [Category C] (X : I → C) (p : I → J)
(c : ∀ (j : J), Cofan (fun (i : p ⁻¹' {j}) => X i))
(hc : ∀ (j : J), IsColimit (c j))
(c' : Cofan (fun j => (c j).pt))
(hc' : IsColimit c')
def cofanCombine : Cofan X := Cofan.mk c'.pt (fun i => (c (p i)).inj ⟨i, rfl⟩ ≫ c'.inj _)
def isColimitCofanCombine : IsColimit (cofanCombine X p c c') := sorry
Actually, this variant could be added first in CategoryTheory.GradedObject
because this would basically show how GradedObject.total
interacts with GradedObject.map
.
Christian Merten (Feb 08 2024 at 16:01):
Thanks!
Joël Riou said:
Actually, this variant could be added first in
CategoryTheory.GradedObject
because this would basically show howGradedObject.total
interacts withGradedObject.map
.
Are you saying that GradedObject.isColimitCofanMapObjComp
should be deduced from the variant you gave above?
Christian Merten (Feb 08 2024 at 16:07):
And this is the code for the sigma types using your combineCofan
from above:
variable {J C : Type*} [Category C] (t : J → Type)
(X : (i : J) → (a : t i) → C)
(c : ∀ (i : J), Cofan (X i))
(hc : ∀ (i : J), IsColimit (c i))
(c' : Cofan (fun j => (c j).pt))
(hc' : IsColimit c')
@[simp]
def fooequiv0 (i : J) : @Sigma.fst _ t ⁻¹' {i} ≃ t i where
toFun := by rintro ⟨⟨j, a⟩, rfl : j = i⟩; exact a
invFun a := ⟨⟨i, a⟩, rfl⟩
left_inv := by rintro ⟨⟨j, a⟩, rfl : j = i⟩; rfl
right_inv x := rfl
def fooequiv2 (i : J) :
((Discrete.equivalence (fooequiv0 t i)).functor ⋙ Discrete.functor (X i))
≅ Discrete.functor (Sigma.uncurry X ∘ Subtype.val) := by
apply Discrete.natIso
rintro ⟨⟨⟨j, a⟩, rfl : j = i⟩⟩
exact eqToIso rfl
def fooequiv3 (i : J) :
Cofan (X i) ≌ Cofan (fun (⟨⟨j, a⟩, _⟩ : Sigma.fst⁻¹' {i}) => X j a) :=
Cocones.equivalenceOfReindexing (Discrete.equivalence (fooequiv0 t i)) (fooequiv2 t X i)
def cofanCombine' : Cofan (Sigma.uncurry X) :=
cofanCombine (Sigma.uncurry X) (fun ⟨i, _⟩ => i)
(fun i => (fooequiv3 t X i).functor.obj (c i)) c'
def isColimitCofanCombine' : IsColimit (cofanCombine' t X c c') := by
apply isColimitCofanCombine
· intro j
apply (IsColimit.ofCoconeEquiv (fooequiv3 t X j)).symm (hc j)
· exact hc'
I still need some auxiliary equivs, can this be avoided? The issue is that Cocones.equivalenceOfReindexing
seems to be quite slow.
Joël Riou (Feb 08 2024 at 18:31):
Christian Merten said:
Are you saying that
GradedObject.isColimitCofanMapObjComp
should be deduced from the variant you gave above?
If it is convenient to do so, this could be a good idea.
The ingredients you suggest all seem relevant to me. However, I ended up with a more simple definition of cofanCombine'
which is not defeq to yours:
variable {J C : Type*} [Category C] (t : J → Type*)
(X : (i : J) → (a : t i) → C) (c : ∀ (i : J), Cofan (X i)) (hc : ∀ (i : J), IsColimit (c i))
(c' : Cofan (fun j => (c j).pt)) (hc' : IsColimit c')
def cofanCombine' : Cofan (Sigma.uncurry X) :=
Cofan.mk c'.pt (fun x => (c x.1).inj x.2 ≫ c'.inj x.1)
As the definition here is quite basic, it would make sense to put the necessary auxiliary definitions inside the definition of isColimitCofanCombine'
.
Christian Merten (Feb 08 2024 at 20:41):
The reason why I defined cofanCombine'
as above, was because then isColimitCofanCombine
applies directly. With your cofanCombine'
I need to show an isomorphism with my version to apply isColimitCofanCombine
. All of this makes we wonder if its worth the going back and forth with equivalences, because this:
variable {J C : Type*} [Category C] (t : J → Type*)
(X : (i : J) → (a : t i) → C) (c : ∀ (i : J), Cofan (X i)) (hc : ∀ (i : J), IsColimit (c i))
(c' : Cofan (fun j => (c j).pt)) (hc' : IsColimit c')
@[simp]
def cofanCombine' : Cofan (Sigma.uncurry X) :=
Cofan.mk c'.pt (fun x => (c x.1).inj x.2 ≫ c'.inj x.1)
def isColimitCofanCombine'' : IsColimit (cofanCombine' t X c c') := mkCofanColimit _
(fun s => Cofan.IsColimit.desc hc' <| fun j ↦ by
apply Cofan.IsColimit.desc (hc j) (fun a ↦ s.inj ⟨j, a⟩))
(fun s => by aesop)
(fun s m hm => Cofan.IsColimit.hom_ext hc' _ _ <| fun j ↦ by
refine Cofan.IsColimit.hom_ext (hc j) _ _ (fun j ↦ ?_)
simp only [← hm, Cofan.IsColimit.fac, cofanCombine', cofan_mk_inj, Category.assoc])
is shorter than anything I have done before using isColimitCofanCombine
.
Joël Riou (Feb 08 2024 at 21:47):
This looks good to me.
Last updated: May 02 2025 at 03:31 UTC