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.GradedObjectbecause this would basically show howGradedObject.totalinteracts 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.isColimitCofanMapObjCompshould 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