l3lab/ntp-mathlib huggingface dataset:
theorem desc_op_comp_opCoproductIsoProduct_hom {X : C} (π : (a : α) → Z a ⟶ X) :
    (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift (fun a ↦ (π a).op) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasCoproduct Z
X : C
π : (a : α) → Z a ⟶ X
⊢ (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift fun a => (π a).op

Next tactic:
convert desc_op_comp_opCoproductIsoProduct'_hom (coproductIsCoproduct Z)
    (productIsProduct (op <| Z ·)) (Cofan.mk _ π)
theorem desc_op_comp_opCoproductIsoProduct_hom {X : C} (π : (a : α) → Z a ⟶ X) :
    (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift (fun a ↦ (π a).op) := by
  convert desc_op_comp_opCoproductIsoProduct'_hom (coproductIsCoproduct Z)
    (productIsProduct (op <| Z ·)) (Cofan.mk _ π)
  · 

Proof state:
case h.e'_2.h.h.e'_6.h.h.e'_5.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasCoproduct Z
X : C
π : (a : α) → Z a ⟶ X
e_1✝ :
  (op X ⟶ ∏ fun x => op (Z x)) = (op (Cofan.mk X π).pt ⟶ (Fan.mk (∏ fun x => op (Z x)) (Pi.π fun x => op (Z x))).pt)
e_3✝¹ : op X = op (Cofan.mk X π).pt
e_4✝¹ : op (∐ fun b => Z b) = op (Cofan.mk (∐ Z) (Sigma.ι Z)).pt
e_3✝ : (∐ fun b => Z b) = (Cofan.mk (∐ Z) (Sigma.ι Z)).pt
e_4✝ : X = (Cofan.mk X π).pt
⊢ Sigma.desc π = IsColimit.desc (coproductIsCoproduct Z) (Cofan.mk X π)

Next tactic:
ext
theorem desc_op_comp_opCoproductIsoProduct_hom {X : C} (π : (a : α) → Z a ⟶ X) :
    (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift (fun a ↦ (π a).op) := by
  convert desc_op_comp_opCoproductIsoProduct'_hom (coproductIsCoproduct Z)
    (productIsProduct (op <| Z ·)) (Cofan.mk _ π)
  · ext; 

Proof state:
case h.e'_2.h.h.e'_6.h.h.e'_5.h.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasCoproduct Z
X : C
π : (a : α) → Z a ⟶ X
e_1✝ :
  (op X ⟶ ∏ fun x => op (Z x)) = (op (Cofan.mk X π).pt ⟶ (Fan.mk (∏ fun x => op (Z x)) (Pi.π fun x => op (Z x))).pt)
e_3✝¹ : op X = op (Cofan.mk X π).pt
e_4✝¹ : op (∐ fun b => Z b) = op (Cofan.mk (∐ Z) (Sigma.ι Z)).pt
e_3✝ : (∐ fun b => Z b) = (Cofan.mk (∐ Z) (Sigma.ι Z)).pt
e_4✝ : X = (Cofan.mk X π).pt
b✝ : α
⊢ Sigma.ι (fun b => Z b) b✝ ≫ Sigma.desc π =
    Sigma.ι (fun b => Z b) b✝ ≫ IsColimit.desc (coproductIsCoproduct Z) (Cofan.mk X π)

Next tactic:
simp [Sigma.desc, colimit.desc, coproductIsCoproduct]
theorem desc_op_comp_opCoproductIsoProduct_hom {X : C} (π : (a : α) → Z a ⟶ X) :
    (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift (fun a ↦ (π a).op) := by
  convert desc_op_comp_opCoproductIsoProduct'_hom (coproductIsCoproduct Z)
    (productIsProduct (op <| Z ·)) (Cofan.mk _ π)
  · ext; simp [Sigma.desc, colimit.desc, coproductIsCoproduct]
  · 

Proof state:
case h.e'_3.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasCoproduct Z
X : C
π : (a : α) → Z a ⟶ X
e_1✝ :
  (op X ⟶ ∏ fun x => op (Z x)) = (op (Cofan.mk X π).pt ⟶ (Fan.mk (∏ fun x => op (Z x)) (Pi.π fun x => op (Z x))).pt)
⊢ (Pi.lift fun a => (π a).op) = IsLimit.lift (productIsProduct fun x => op (Z x)) (Cofan.op (Cofan.mk X π))

Next tactic:
ext
theorem desc_op_comp_opCoproductIsoProduct_hom {X : C} (π : (a : α) → Z a ⟶ X) :
    (Sigma.desc π).op ≫ (opCoproductIsoProduct Z).hom = Pi.lift (fun a ↦ (π a).op) := by
  convert desc_op_comp_opCoproductIsoProduct'_hom (coproductIsCoproduct Z)
    (productIsProduct (op <| Z ·)) (Cofan.mk _ π)
  · ext; simp [Sigma.desc, colimit.desc, coproductIsCoproduct]
  · ext; 

Proof state:
case h.e'_3.h.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasCoproduct Z
X : C
π : (a : α) → Z a ⟶ X
e_1✝ :
  (op X ⟶ ∏ fun x => op (Z x)) = (op (Cofan.mk X π).pt ⟶ (Fan.mk (∏ fun x => op (Z x)) (Pi.π fun x => op (Z x))).pt)
b✝ : α
⊢ (Pi.lift fun a => (π a).op) ≫ Pi.π (fun a => op (Z a)) b✝ =
    IsLimit.lift (productIsProduct fun x => op (Z x)) (Cofan.op (Cofan.mk X π)) ≫ Pi.π (fun a => op (Z a)) b✝

Next tactic:
simp [Pi.lift, limit.lift, productIsProduct]
instance : HasCoproduct (op <| Z ·) := hasColimitOfIso
  ((Discrete.natIsoFunctor ≪≫ Discrete.natIso (fun _ ↦ by 

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
x✝ : Discrete α
⊢ (Discrete.functor (((Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op).toPrefunctor.obj ∘ Discrete.mk)).obj x✝ ≅
    (Discrete.functor fun x => op (Z x)).obj x✝

Next tactic:
rfl
/-- If a `Fan` is limit, then its opposite is colimit. -/
def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
hf : IsLimit f
⊢ IsColimit (Fan.op f)

Next tactic:
let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙
    (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _)
/-- If a `Fan` is limit, then its opposite is colimit. -/
def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by
  let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙
    (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _)
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
hf : IsLimit f
e : (Discrete.functor fun x => Opposite.op (Z x)) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op :=
  Discrete.natIso fun x => Iso.refl ((Discrete.functor fun x => Opposite.op (Z x)).obj x)
⊢ IsColimit (Fan.op f)

Next tactic:
refine IsColimit.ofIsoColimit ((IsColimit.precomposeHomEquiv e _).2
    (IsColimit.whiskerEquivalence hf.op (Discrete.opposite α).symm))
    (Cocones.ext (Iso.refl _) (fun ⟨a⟩ ↦ ?_))
/-- If a `Fan` is limit, then its opposite is colimit. -/
def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by
  let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙
    (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _)
  refine IsColimit.ofIsoColimit ((IsColimit.precomposeHomEquiv e _).2
    (IsColimit.whiskerEquivalence hf.op (Discrete.opposite α).symm))
    (Cocones.ext (Iso.refl _) (fun ⟨a⟩ ↦ ?_))
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
hf : IsLimit f
e : (Discrete.functor fun x => Opposite.op (Z x)) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op :=
  Discrete.natIso fun x => Iso.refl ((Discrete.functor fun x => Opposite.op (Z x)).obj x)
x✝ : Discrete α
a : α
⊢ ((Cocones.precompose e.hom).obj (Cocone.whisker (Discrete.opposite α).symm.functor (Cone.op f))).ι.app { as := a } ≫
      (Iso.refl
          ((Cocones.precompose e.hom).obj (Cocone.whisker (Discrete.opposite α).symm.functor (Cone.op f))).pt).hom =
    (Fan.op f).ι.app { as := a }

Next tactic:
dsimp
/-- If a `Fan` is limit, then its opposite is colimit. -/
def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by
  let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙
    (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _)
  refine IsColimit.ofIsoColimit ((IsColimit.precomposeHomEquiv e _).2
    (IsColimit.whiskerEquivalence hf.op (Discrete.opposite α).symm))
    (Cocones.ext (Iso.refl _) (fun ⟨a⟩ ↦ ?_))
  dsimp
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
hf : IsLimit f
e : (Discrete.functor fun x => Opposite.op (Z x)) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op :=
  Discrete.natIso fun x => Iso.refl ((Discrete.functor fun x => Opposite.op (Z x)).obj x)
x✝ : Discrete α
a : α
⊢ (𝟙 (Opposite.op (Z a)) ≫ (f.π.app ((Discrete.opposite α).inverse.obj { as := a }).unop).op) ≫ 𝟙 (Opposite.op f.pt) =
    (proj f a).op

Next tactic:
erw [Category.id_comp, Category.comp_id]
/-- If a `Fan` is limit, then its opposite is colimit. -/
def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by
  let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙
    (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _)
  refine IsColimit.ofIsoColimit ((IsColimit.precomposeHomEquiv e _).2
    (IsColimit.whiskerEquivalence hf.op (Discrete.opposite α).symm))
    (Cocones.ext (Iso.refl _) (fun ⟨a⟩ ↦ ?_))
  dsimp
  erw [Category.id_comp, Category.comp_id]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
hf : IsLimit f
e : (Discrete.functor fun x => Opposite.op (Z x)) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op :=
  Discrete.natIso fun x => Iso.refl ((Discrete.functor fun x => Opposite.op (Z x)).obj x)
x✝ : Discrete α
a : α
⊢ (f.π.app ((Discrete.opposite α).inverse.obj { as := a }).unop).op = (proj f a).op

Next tactic:
rfl
theorem opProductIsoCoproduct'_inv_comp_lift {f : Fan Z} {c : Cofan (op <| Z ·)}
    (hf : IsLimit f) (hc : IsColimit c) (f' : Fan Z) :
    (opProductIsoCoproduct' hf hc).inv ≫ (hf.lift f').op = hc.desc f'.op := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
c : Cofan fun x => op (Z x)
hf : IsLimit f
hc : IsColimit c
f' : Fan Z
⊢ (opProductIsoCoproduct' hf hc).inv ≫ (IsLimit.lift hf f').op = IsColimit.desc hc (Fan.op f')

Next tactic:
refine (Iso.inv_comp_eq _).mpr (Quiver.Hom.unop_inj (hf.hom_ext (fun ⟨j⟩ ↦ Quiver.Hom.op_inj ?_)))
theorem opProductIsoCoproduct'_inv_comp_lift {f : Fan Z} {c : Cofan (op <| Z ·)}
    (hf : IsLimit f) (hc : IsColimit c) (f' : Fan Z) :
    (opProductIsoCoproduct' hf hc).inv ≫ (hf.lift f').op = hc.desc f'.op := by
  refine (Iso.inv_comp_eq _).mpr (Quiver.Hom.unop_inj (hf.hom_ext (fun ⟨j⟩ ↦ Quiver.Hom.op_inj ?_)))
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
c : Cofan fun x => op (Z x)
hf : IsLimit f
hc : IsColimit c
f' : Fan Z
x✝ : Discrete α
j : α
⊢ ((IsLimit.lift hf f').op.unop ≫ f.π.app { as := j }).op =
    (((opProductIsoCoproduct' hf hc).hom ≫ IsColimit.desc hc (Fan.op f')).unop ≫ f.π.app { as := j }).op

Next tactic:
simp only [Discrete.functor_obj, unop_op, Quiver.Hom.unop_op, IsLimit.fac, Fan.op, unop_comp,
    Category.assoc, op_comp, op_unop, Quiver.Hom.op_unop]
theorem opProductIsoCoproduct'_inv_comp_lift {f : Fan Z} {c : Cofan (op <| Z ·)}
    (hf : IsLimit f) (hc : IsColimit c) (f' : Fan Z) :
    (opProductIsoCoproduct' hf hc).inv ≫ (hf.lift f').op = hc.desc f'.op := by
  refine (Iso.inv_comp_eq _).mpr (Quiver.Hom.unop_inj (hf.hom_ext (fun ⟨j⟩ ↦ Quiver.Hom.op_inj ?_)))
  simp only [Discrete.functor_obj, unop_op, Quiver.Hom.unop_op, IsLimit.fac, Fan.op, unop_comp,
    Category.assoc, op_comp, op_unop, Quiver.Hom.op_unop]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
c : Cofan fun x => op (Z x)
hf : IsLimit f
hc : IsColimit c
f' : Fan Z
x✝ : Discrete α
j : α
⊢ (f'.π.app { as := j }).op =
    (f.π.app { as := j }).op ≫
      (opProductIsoCoproduct' hf hc).hom ≫ IsColimit.desc hc (Cofan.mk (op f'.pt) fun a => (Fan.proj f' a).op)

Next tactic:
erw [← Category.assoc, proj_comp_opProductIsoCoproduct'_hom, IsColimit.fac]
theorem opProductIsoCoproduct'_inv_comp_lift {f : Fan Z} {c : Cofan (op <| Z ·)}
    (hf : IsLimit f) (hc : IsColimit c) (f' : Fan Z) :
    (opProductIsoCoproduct' hf hc).inv ≫ (hf.lift f').op = hc.desc f'.op := by
  refine (Iso.inv_comp_eq _).mpr (Quiver.Hom.unop_inj (hf.hom_ext (fun ⟨j⟩ ↦ Quiver.Hom.op_inj ?_)))
  simp only [Discrete.functor_obj, unop_op, Quiver.Hom.unop_op, IsLimit.fac, Fan.op, unop_comp,
    Category.assoc, op_comp, op_unop, Quiver.Hom.op_unop]
  erw [← Category.assoc, proj_comp_opProductIsoCoproduct'_hom, IsColimit.fac]
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
f : Fan Z
c : Cofan fun x => op (Z x)
hf : IsLimit f
hc : IsColimit c
f' : Fan Z
x✝ : Discrete α
j : α
⊢ (f'.π.app { as := j }).op = (Cofan.mk (op f'.pt) fun a => (Fan.proj f' a).op).ι.app { as := j }

Next tactic:
rfl
theorem opProductIsoCoproduct_inv_comp_lift {X : C} (π : (a : α) → X ⟶ Z a) :
    (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op  = Sigma.desc (fun a ↦ (π a).op) := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
X : C
π : (a : α) → X ⟶ Z a
⊢ (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op = Sigma.desc fun a => (π a).op

Next tactic:
convert opProductIsoCoproduct'_inv_comp_lift (productIsProduct Z)
    (coproductIsCoproduct (op <| Z ·)) (Fan.mk _ π)
theorem opProductIsoCoproduct_inv_comp_lift {X : C} (π : (a : α) → X ⟶ Z a) :
    (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op  = Sigma.desc (fun a ↦ (π a).op) := by
  convert opProductIsoCoproduct'_inv_comp_lift (productIsProduct Z)
    (coproductIsCoproduct (op <| Z ·)) (Fan.mk _ π)
  · 

Proof state:
case h.e'_2.h.h.e'_7.h.h.e'_5.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
X : C
π : (a : α) → X ⟶ Z a
e_1✝ :
  ((∐ fun x => op (Z x)) ⟶ op X) =
    ((Cofan.mk (∐ fun x => op (Z x)) (Sigma.ι fun x => op (Z x))).pt ⟶ op (Fan.mk X π).pt)
e_4✝¹ : op (∏ Z) = op (Fan.mk (∏ Z) (Pi.π Z)).pt
e_5✝ : op X = op (Fan.mk X π).pt
e_3✝ : X = (Fan.mk X π).pt
e_4✝ : (∏ fun b => Z b) = (Fan.mk (∏ Z) (Pi.π Z)).pt
⊢ Pi.lift π = IsLimit.lift (productIsProduct Z) (Fan.mk X π)

Next tactic:
ext
theorem opProductIsoCoproduct_inv_comp_lift {X : C} (π : (a : α) → X ⟶ Z a) :
    (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op  = Sigma.desc (fun a ↦ (π a).op) := by
  convert opProductIsoCoproduct'_inv_comp_lift (productIsProduct Z)
    (coproductIsCoproduct (op <| Z ·)) (Fan.mk _ π)
  · ext; 

Proof state:
case h.e'_2.h.h.e'_7.h.h.e'_5.h.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
X : C
π : (a : α) → X ⟶ Z a
e_1✝ :
  ((∐ fun x => op (Z x)) ⟶ op X) =
    ((Cofan.mk (∐ fun x => op (Z x)) (Sigma.ι fun x => op (Z x))).pt ⟶ op (Fan.mk X π).pt)
e_4✝¹ : op (∏ Z) = op (Fan.mk (∏ Z) (Pi.π Z)).pt
e_5✝ : op X = op (Fan.mk X π).pt
e_3✝ : X = (Fan.mk X π).pt
e_4✝ : (∏ fun b => Z b) = (Fan.mk (∏ Z) (Pi.π Z)).pt
b✝ : α
⊢ Pi.lift π ≫ Pi.π (fun b => Z b) b✝ = IsLimit.lift (productIsProduct Z) (Fan.mk X π) ≫ Pi.π (fun b => Z b) b✝

Next tactic:
simp [Pi.lift, limit.lift, productIsProduct]
theorem opProductIsoCoproduct_inv_comp_lift {X : C} (π : (a : α) → X ⟶ Z a) :
    (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op  = Sigma.desc (fun a ↦ (π a).op) := by
  convert opProductIsoCoproduct'_inv_comp_lift (productIsProduct Z)
    (coproductIsCoproduct (op <| Z ·)) (Fan.mk _ π)
  · ext; simp [Pi.lift, limit.lift, productIsProduct]
  · 

Proof state:
case h.e'_3.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
X : C
π : (a : α) → X ⟶ Z a
e_1✝ :
  ((∐ fun x => op (Z x)) ⟶ op X) =
    ((Cofan.mk (∐ fun x => op (Z x)) (Sigma.ι fun x => op (Z x))).pt ⟶ op (Fan.mk X π).pt)
⊢ (Sigma.desc fun a => (π a).op) = IsColimit.desc (coproductIsCoproduct fun x => op (Z x)) (Fan.op (Fan.mk X π))

Next tactic:
ext
theorem opProductIsoCoproduct_inv_comp_lift {X : C} (π : (a : α) → X ⟶ Z a) :
    (opProductIsoCoproduct Z).inv ≫ (Pi.lift π).op  = Sigma.desc (fun a ↦ (π a).op) := by
  convert opProductIsoCoproduct'_inv_comp_lift (productIsProduct Z)
    (coproductIsCoproduct (op <| Z ·)) (Fan.mk _ π)
  · ext; simp [Pi.lift, limit.lift, productIsProduct]
  · ext; 

Proof state:
case h.e'_3.h.h
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X✝ : Type v₂
α : Type u_1
Z : α → C
inst✝ : HasProduct Z
X : C
π : (a : α) → X ⟶ Z a
e_1✝ :
  ((∐ fun x => op (Z x)) ⟶ op X) =
    ((Cofan.mk (∐ fun x => op (Z x)) (Sigma.ι fun x => op (Z x))).pt ⟶ op (Fan.mk X π).pt)
b✝ : α
⊢ (Sigma.ι (fun a => op (Z a)) b✝ ≫ Sigma.desc fun a => (π a).op) =
    Sigma.ι (fun a => op (Z a)) b✝ ≫ IsColimit.desc (coproductIsCoproduct fun x => op (Z x)) (Fan.op (Fan.mk X π))

Next tactic:
simp [Sigma.desc, colimit.desc, coproductIsCoproduct]
instance hasEqualizers_opposite [HasCoequalizers C] : HasEqualizers Cᵒᵖ := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasCoequalizers C
⊢ HasEqualizers Cᵒᵖ

Next tactic:
haveI : HasColimitsOfShape WalkingParallelPairᵒᵖ C :=
    hasColimitsOfShape_of_equivalence walkingParallelPairOpEquiv
instance hasEqualizers_opposite [HasCoequalizers C] : HasEqualizers Cᵒᵖ := by
  haveI : HasColimitsOfShape WalkingParallelPairᵒᵖ C :=
    hasColimitsOfShape_of_equivalence walkingParallelPairOpEquiv
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasCoequalizers C
this : HasColimitsOfShape WalkingParallelPairᵒᵖ C
⊢ HasEqualizers Cᵒᵖ

Next tactic:
infer_instance
instance hasCoequalizers_opposite [HasEqualizers C] : HasCoequalizers Cᵒᵖ := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasEqualizers C
⊢ HasCoequalizers Cᵒᵖ

Next tactic:
haveI : HasLimitsOfShape WalkingParallelPairᵒᵖ C :=
    hasLimitsOfShape_of_equivalence walkingParallelPairOpEquiv
instance hasCoequalizers_opposite [HasEqualizers C] : HasCoequalizers Cᵒᵖ := by
  haveI : HasLimitsOfShape WalkingParallelPairᵒᵖ C :=
    hasLimitsOfShape_of_equivalence walkingParallelPairOpEquiv
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasEqualizers C
this : HasLimitsOfShape WalkingParallelPairᵒᵖ C
⊢ HasCoequalizers Cᵒᵖ

Next tactic:
infer_instance
instance hasPullbacks_opposite [HasPushouts C] : HasPullbacks Cᵒᵖ := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasPushouts C
⊢ HasPullbacks Cᵒᵖ

Next tactic:
haveI : HasColimitsOfShape WalkingCospanᵒᵖ C :=
    hasColimitsOfShape_of_equivalence walkingCospanOpEquiv.symm
instance hasPullbacks_opposite [HasPushouts C] : HasPullbacks Cᵒᵖ := by
  haveI : HasColimitsOfShape WalkingCospanᵒᵖ C :=
    hasColimitsOfShape_of_equivalence walkingCospanOpEquiv.symm
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasPushouts C
this : HasColimitsOfShape WalkingCospanᵒᵖ C
⊢ HasPullbacks Cᵒᵖ

Next tactic:
apply hasLimitsOfShape_op_of_hasColimitsOfShape
instance hasPushouts_opposite [HasPullbacks C] : HasPushouts Cᵒᵖ := by
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasPullbacks C
⊢ HasPushouts Cᵒᵖ

Next tactic:
haveI : HasLimitsOfShape WalkingSpanᵒᵖ C :=
    hasLimitsOfShape_of_equivalence walkingSpanOpEquiv.symm
instance hasPushouts_opposite [HasPullbacks C] : HasPushouts Cᵒᵖ := by
  haveI : HasLimitsOfShape WalkingSpanᵒᵖ C :=
    hasLimitsOfShape_of_equivalence walkingSpanOpEquiv.symm
  

Proof state:
C : Type u₁
inst✝² : Category.{v₁, u₁} C
J : Type u₂
inst✝¹ : Category.{v₂, u₂} J
X : Type v₂
inst✝ : HasPullbacks C
this : HasLimitsOfShape WalkingSpanᵒᵖ C
⊢ HasPushouts Cᵒᵖ

Next tactic:
infer_instance
/-- The canonical isomorphism relating `Span f.op g.op` and `(Cospan f g).op` -/
@[simps!]
def spanOp {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) :
    span f.op g.op ≅ walkingCospanOpEquiv.inverse ⋙ (cospan f g).op :=
  NatIso.ofComponents (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Type u₂
inst✝ : Category.{v₂, u₂} J
X✝ : Type v₂
X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
⊢ (X_1 : WalkingSpan) → (span f.op g.op).obj X_1 ≅ (walkingCospanOpEquiv.inverse ⋙ (cospan f g).op).obj X_1

Next tactic:
rintro (_ | _ | _)
/-- The canonical isomorphism relating `Span f.op g.op` and `(Cospan f g).op` -/
@[simps!]
def spanOp {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) :
    span f.op g.op ≅ walkingCospanOpEquiv.inverse ⋙ (cospan f g).op :=
  NatIso.ofComponents (by rintro (_ | _ | _) <;> 

Proof state:
case none
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Type u₂
inst✝ : Category.{v₂, u₂} J
X✝ : Type v₂
X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
⊢ (span f.op g.op).obj none ≅ (walkingCospanOpEquiv.inverse ⋙ (cospan f g).op).obj none

Next tactic:
rfl
/-- The canonical isomorphism relating `Span f.op g.op` and `(Cospan f g).op` -/
@[simps!]
def spanOp {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) :
    span f.op g.op ≅ walkingCospanOpEquiv.inverse ⋙ (cospan f g).op :=
  NatIso.ofComponents (by rintro (_ | _ | _) <;> 

Proof state:
case some.left
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Type u₂
inst✝ : Category.{v₂, u₂} J
X✝ : Type v₂
X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
⊢ (span f.op g.op).obj (some WalkingPair.left) ≅
    (walkingCospanOpEquiv.inverse ⋙ (cospan f g).op).obj (some WalkingPair.left)

Next tactic:
rfl
/-- The canonical isomorphism relating `Span f.op g.op` and `(Cospan f g).op` -/
@[simps!]
def spanOp {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) :
    span f.op g.op ≅ walkingCospanOpEquiv.inverse ⋙ (cospan f g).op :=
  NatIso.ofComponents (by rintro (_ | _ | _) <;> 

Proof state:
case some.right
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Type u₂
inst✝ : Category.{v₂, u₂} J
X✝ : Type v₂
X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
⊢ (span f.op g.op).obj (some WalkingPair.right) ≅
    (walkingCospanOpEquiv.inverse ⋙ (cospan f g).op).obj (some WalkingPair.right)

Next tactic:
rfl
/-- The canonical isomorphism relating `Span f.op g.op` and `(Cospan f g).op` -/
@[simps!]
def spanOp {X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) :
    span f.op g.op ≅ walkingCospanOpEquiv.inverse ⋙ (cospan f g).op :=
  NatIso.ofComponents (by rintro (_ | _ | _) <;> rfl)
    (by 

Proof state:
C : Type u₁
inst✝¹ : Category.{v₁, u₁} C
J : Type u₂
inst✝ : Category.{v₂, u₂} J
X✝ : Type v₂
X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
⊢ ∀ {X_1 Y_1 : WalkingSpan} (f_1 : X_1 ⟶ Y_1),
    (span f.op g.op).map f_1 ≫
        (Option.casesOn Y_1 (Iso.refl ((span f.op g.op).obj none)) fun val =>
            WalkingPair.casesOn val (Iso.refl ((span f.op g.op).obj (some WalkingPair.left)))
              (Iso.refl ((span f.op g.op).obj (some WalkingPair.right)))).hom =
      (Option.casesOn X_1 (Iso.refl ((span f.op g.op).obj none)) fun val =>
            WalkingPair.casesOn val (Iso.refl ((span f.op g.op).obj (some WalkingPair.left)))
              (Iso.refl ((span f.op g.op).obj (some WalkingPair.right)))).hom ≫
        (walkingCospanOpEquiv.inverse ⋙ (cospan f g).op).map f_1

Next tactic:
rintro (_ | _ | _) (_ | _ | _) f