l3lab/ntp-mathlib huggingface dataset:
/-- The underlying cocone of a cokernel cofork is mapped to a colimit cocone if and only if
the mapped cokernel cofork is colimit. -/
def isColimitMapCoconeEquiv :
    IsColimit (G.mapCocone c) ≃ IsColimit (c.map G) := by
  refine' (IsColimit.precomposeHomEquiv _ _).symm.trans (IsColimit.equivIsoColimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> simp
  exact Cocones.ext (Iso.refl _) (by rintro (_|_) <;> 

Proof state:
case one
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
f : X ⟶ Y
c : CokernelCofork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ ((Cocones.precompose
                  (parallelPair.ext (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.zero))
                      (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.one))
                      (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                      (_ : 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map 0)).hom).obj
              (G.mapCocone c)).ι.app
        WalkingParallelPair.one ≫
      (Iso.refl
          ((Cocones.precompose
                  (parallelPair.ext (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.zero))
                      (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.one))
                      (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                      (_ : 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map 0)).hom).obj
              (G.mapCocone c)).pt).hom =
    (map c G).ι.app WalkingParallelPair.one

Next tactic:
aesop_cat
/-- The map of a cokernel cofork is a colimit iff
the cokernel cofork consisting of the mapped morphisms is a colimit.
This essentially lets us commute `CokernelCofork.ofπ` with `Functor.mapCocone`.

This is a variant of `isColimitMapCoconeCoforkEquiv` for equalizers,
which we can't use directly between `G.map 0 = 0` does not hold definitionally.
-/
def isColimitMapCoconeCoforkEquiv' :
    IsColimit (G.mapCocone (CokernelCofork.ofπ h w)) ≃
      IsColimit
        (CokernelCofork.ofπ (G.map h) (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
⊢ G.map f ≫ G.map h = 0

Next tactic:
simp only [← G.map_comp, w, Functor.map_zero]
/-- The property of preserving cokernels expressed in terms of cokernel coforks.

This is a variant of `isColimitCoforkMapOfIsColimit` for equalizers,
which we can't use directly between `G.map 0 = 0` does not hold definitionally.
-/
def isColimitCoforkMapOfIsColimit' [PreservesColimit (parallelPair f 0) G]
    (l : IsColimit (CokernelCofork.ofπ h w)) :
    IsColimit
      (CokernelCofork.ofπ (G.map h) (by 

Proof state:
C : Type u₁
inst✝⁵ : Category.{v₁, u₁} C
inst✝⁴ : HasZeroMorphisms C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
inst✝² : HasZeroMorphisms D
G : C ⥤ D
inst✝¹ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝ : PreservesColimit (parallelPair f 0) G
l : IsColimit (CokernelCofork.ofπ h w)
⊢ G.map f ≫ G.map h = 0

Next tactic:
simp only [← G.map_comp, w, Functor.map_zero]
/--
If `G` preserves cokernels and `C` has them, then the cofork constructed of the mapped morphisms of
a cokernel cofork is a colimit.
-/
def isColimitOfHasCokernelOfPreservesColimit [PreservesColimit (parallelPair f 0) G] :
    IsColimit
      (Cofork.ofπ (G.map (cokernel.π f))
          (by 

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : HasZeroMorphisms C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasZeroMorphisms D
G : C ⥤ D
inst✝² : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝¹ : HasCokernel f
inst✝ : PreservesColimit (parallelPair f 0) G
⊢ G.map f ≫ G.map (cokernel.π f) = 0 ≫ G.map (cokernel.π f)

Next tactic:
simp only [← G.map_comp, cokernel.condition, zero_comp, Functor.map_zero]
/-- If the cokernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
cokernel of `f`.
-/
def PreservesCokernel.ofIsoComparison [i : IsIso (cokernelComparison f G)] :
    PreservesColimit (parallelPair f 0) G := by
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : HasZeroMorphisms C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasZeroMorphisms D
G : C ⥤ D
inst✝² : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝¹ : HasCokernel f
inst✝ : HasCokernel (G.map f)
i : IsIso (cokernelComparison f G)
⊢ PreservesColimit (parallelPair f 0) G

Next tactic:
apply preservesColimitOfPreservesColimitCocone (cokernelIsCokernel f)
/-- If the cokernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
cokernel of `f`.
-/
def PreservesCokernel.ofIsoComparison [i : IsIso (cokernelComparison f G)] :
    PreservesColimit (parallelPair f 0) G := by
  apply preservesColimitOfPreservesColimitCocone (cokernelIsCokernel f)
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : HasZeroMorphisms C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasZeroMorphisms D
G : C ⥤ D
inst✝² : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝¹ : HasCokernel f
inst✝ : HasCokernel (G.map f)
i : IsIso (cokernelComparison f G)
⊢ IsColimit (G.mapCocone (Cofork.ofπ (cokernel.π f) (_ : f ≫ cokernel.π f = 0 ≫ cokernel.π f)))

Next tactic:
apply (isColimitMapCoconeCoforkEquiv' G (cokernel.condition f)).symm _
/-- If the cokernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
cokernel of `f`.
-/
def PreservesCokernel.ofIsoComparison [i : IsIso (cokernelComparison f G)] :
    PreservesColimit (parallelPair f 0) G := by
  apply preservesColimitOfPreservesColimitCocone (cokernelIsCokernel f)
  apply (isColimitMapCoconeCoforkEquiv' G (cokernel.condition f)).symm _
  

Proof state:
C : Type u₁
inst✝⁶ : Category.{v₁, u₁} C
inst✝⁵ : HasZeroMorphisms C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
inst✝³ : HasZeroMorphisms D
G : C ⥤ D
inst✝² : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝¹ : HasCokernel f
inst✝ : HasCokernel (G.map f)
i : IsIso (cokernelComparison f G)
⊢ IsColimit (CokernelCofork.ofπ (G.map (cokernel.π f)) (_ : G.map f ≫ G.map (cokernel.π f) = 0))

Next tactic:
exact @IsColimit.ofPointIso _ _ _ _ _ _ _ (cokernelIsCokernel (G.map f)) i
@[simp]
theorem PreservesCokernel.iso_inv : (PreservesCokernel.iso G f).inv = cokernelComparison f G := by
  

Proof state:
C : Type u₁
inst✝⁷ : Category.{v₁, u₁} C
inst✝⁶ : HasZeroMorphisms C
D : Type u₂
inst✝⁵ : Category.{v₂, u₂} D
inst✝⁴ : HasZeroMorphisms D
G : C ⥤ D
inst✝³ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝² : HasCokernel f
inst✝¹ : HasCokernel (G.map f)
inst✝ : PreservesColimit (parallelPair f 0) G
⊢ (iso G f).inv = cokernelComparison f G

Next tactic:
rw [← cancel_epi (cokernel.π _)]
@[simp]
theorem PreservesCokernel.iso_inv : (PreservesCokernel.iso G f).inv = cokernelComparison f G := by
  rw [← cancel_epi (cokernel.π _)]
  

Proof state:
C : Type u₁
inst✝⁷ : Category.{v₁, u₁} C
inst✝⁶ : HasZeroMorphisms C
D : Type u₂
inst✝⁵ : Category.{v₂, u₂} D
inst✝⁴ : HasZeroMorphisms D
G : C ⥤ D
inst✝³ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝² : HasCokernel f
inst✝¹ : HasCokernel (G.map f)
inst✝ : PreservesColimit (parallelPair f 0) G
⊢ cokernel.π (G.map f) ≫ (iso G f).inv = cokernel.π (G.map f) ≫ cokernelComparison f G

Next tactic:
simp [PreservesCokernel.iso]
instance : IsIso (cokernelComparison f G) := by
  

Proof state:
C : Type u₁
inst✝⁷ : Category.{v₁, u₁} C
inst✝⁶ : HasZeroMorphisms C
D : Type u₂
inst✝⁵ : Category.{v₂, u₂} D
inst✝⁴ : HasZeroMorphisms D
G : C ⥤ D
inst✝³ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝² : HasCokernel f
inst✝¹ : HasCokernel (G.map f)
inst✝ : PreservesColimit (parallelPair f 0) G
⊢ IsIso (cokernelComparison f G)

Next tactic:
rw [← PreservesCokernel.iso_inv]
instance : IsIso (cokernelComparison f G) := by
  rw [← PreservesCokernel.iso_inv]
  

Proof state:
C : Type u₁
inst✝⁷ : Category.{v₁, u₁} C
inst✝⁶ : HasZeroMorphisms C
D : Type u₂
inst✝⁵ : Category.{v₂, u₂} D
inst✝⁴ : HasZeroMorphisms D
G : C ⥤ D
inst✝³ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝² : HasCokernel f
inst✝¹ : HasCokernel (G.map f)
inst✝ : PreservesColimit (parallelPair f 0) G
⊢ IsIso (PreservesCokernel.iso G f).inv

Next tactic:
infer_instance
@[reassoc]
theorem preserves_cokernel_iso_comp_cokernel_map {X' Y' : C} (g : X' ⟶ Y') [HasCokernel g]
    [HasCokernel (G.map g)] [PreservesColimit (parallelPair g 0) G] (p : X ⟶ X') (q : Y ⟶ Y')
    (hpq : f ≫ q = p ≫ g) :
    (PreservesCokernel.iso G _).hom ≫
        cokernel.map (G.map f) (G.map g) (G.map p) (G.map q)
          (by 

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : HasZeroMorphisms C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : HasZeroMorphisms D
G : C ⥤ D
inst✝⁶ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝⁵ : HasCokernel f
inst✝⁴ : HasCokernel (G.map f)
inst✝³ : PreservesColimit (parallelPair f 0) G
X' Y' : C
g : X' ⟶ Y'
inst✝² : HasCokernel g
inst✝¹ : HasCokernel (G.map g)
inst✝ : PreservesColimit (parallelPair g 0) G
p : X ⟶ X'
q : Y ⟶ Y'
hpq : f ≫ q = p ≫ g
⊢ G.map f ≫ G.map q = G.map p ≫ G.map g

Next tactic:
rw [← G.map_comp, hpq, G.map_comp]
@[reassoc]
theorem preserves_cokernel_iso_comp_cokernel_map {X' Y' : C} (g : X' ⟶ Y') [HasCokernel g]
    [HasCokernel (G.map g)] [PreservesColimit (parallelPair g 0) G] (p : X ⟶ X') (q : Y ⟶ Y')
    (hpq : f ≫ q = p ≫ g) :
    (PreservesCokernel.iso G _).hom ≫
        cokernel.map (G.map f) (G.map g) (G.map p) (G.map q)
          (by rw [← G.map_comp, hpq, G.map_comp]) =
      G.map (cokernel.map f g p q hpq) ≫ (PreservesCokernel.iso G _).hom := by
  

Proof state:
C : Type u₁
inst✝¹⁰ : Category.{v₁, u₁} C
inst✝⁹ : HasZeroMorphisms C
D : Type u₂
inst✝⁸ : Category.{v₂, u₂} D
inst✝⁷ : HasZeroMorphisms D
G : C ⥤ D
inst✝⁶ : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Y ⟶ Z
w : f ≫ h = 0
inst✝⁵ : HasCokernel f
inst✝⁴ : HasCokernel (G.map f)
inst✝³ : PreservesColimit (parallelPair f 0) G
X' Y' : C
g : X' ⟶ Y'
inst✝² : HasCokernel g
inst✝¹ : HasCokernel (G.map g)
inst✝ : PreservesColimit (parallelPair g 0) G
p : X ⟶ X'
q : Y ⟶ Y'
hpq : f ≫ q = p ≫ g
⊢ (PreservesCokernel.iso G f).hom ≫
      cokernel.map (G.map f) (G.map g) (G.map p) (G.map q) (_ : G.map f ≫ G.map q = G.map p ≫ G.map g) =
    G.map (cokernel.map f g p q hpq) ≫ (PreservesCokernel.iso G g).hom

Next tactic:
rw [← Iso.comp_inv_eq, Category.assoc, ← Iso.eq_inv_comp, PreservesCokernel.iso_inv,
    cokernel_map_comp_cokernelComparison, PreservesCokernel.iso_inv]
noncomputable instance preservesKernelZero :
    PreservesLimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cone (parallelPair 0 0)
hc : IsLimit c
⊢ IsLimit (G.mapCone c)

Next tactic:
have := KernelFork.IsLimit.isIso_ι c hc rfl
noncomputable instance preservesKernelZero :
    PreservesLimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := KernelFork.IsLimit.isIso_ι c hc rfl
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cone (parallelPair 0 0)
hc : IsLimit c
this : IsIso (Fork.ι c)
⊢ IsLimit (G.mapCone c)

Next tactic:
refine' (KernelFork.isLimitMapConeEquiv c G).symm _
noncomputable instance preservesKernelZero :
    PreservesLimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := KernelFork.IsLimit.isIso_ι c hc rfl
    refine' (KernelFork.isLimitMapConeEquiv c G).symm _
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cone (parallelPair 0 0)
hc : IsLimit c
this : IsIso (Fork.ι c)
⊢ IsLimit (KernelFork.map c G)

Next tactic:
refine' IsLimit.ofIsoLimit (KernelFork.IsLimit.ofId _ (G.map_zero _ _)) _
noncomputable instance preservesKernelZero :
    PreservesLimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := KernelFork.IsLimit.isIso_ι c hc rfl
    refine' (KernelFork.isLimitMapConeEquiv c G).symm _
    refine' IsLimit.ofIsoLimit (KernelFork.IsLimit.ofId _ (G.map_zero _ _)) _
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cone (parallelPair 0 0)
hc : IsLimit c
this : IsIso (Fork.ι c)
⊢ KernelFork.ofι (𝟙 (G.obj X)) (_ : 𝟙 (G.obj X) ≫ G.map 0 = 0) ≅ KernelFork.map c G

Next tactic:
exact (Fork.ext (G.mapIso (asIso (Fork.ι c))).symm (by simp))
noncomputable instance preservesKernelZero :
    PreservesLimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := KernelFork.IsLimit.isIso_ι c hc rfl
    refine' (KernelFork.isLimitMapConeEquiv c G).symm _
    refine' IsLimit.ofIsoLimit (KernelFork.IsLimit.ofId _ (G.map_zero _ _)) _
    exact (Fork.ext (G.mapIso (asIso (Fork.ι c))).symm (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cone (parallelPair 0 0)
hc : IsLimit c
this : IsIso (Fork.ι c)
⊢ (G.mapIso (asIso (Fork.ι c))).symm.hom ≫ Fork.ι (KernelFork.map c G) =
    Fork.ι (KernelFork.ofι (𝟙 (G.obj X)) (_ : 𝟙 (G.obj X) ≫ G.map 0 = 0))

Next tactic:
simp
noncomputable instance preservesCokernelZero :
    PreservesColimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cocone (parallelPair 0 0)
hc : IsColimit c
⊢ IsColimit (G.mapCocone c)

Next tactic:
have := CokernelCofork.IsColimit.isIso_π c hc rfl
noncomputable instance preservesCokernelZero :
    PreservesColimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := CokernelCofork.IsColimit.isIso_π c hc rfl
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cocone (parallelPair 0 0)
hc : IsColimit c
this : IsIso (Cofork.π c)
⊢ IsColimit (G.mapCocone c)

Next tactic:
refine' (CokernelCofork.isColimitMapCoconeEquiv c G).symm _
noncomputable instance preservesCokernelZero :
    PreservesColimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := CokernelCofork.IsColimit.isIso_π c hc rfl
    refine' (CokernelCofork.isColimitMapCoconeEquiv c G).symm _
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cocone (parallelPair 0 0)
hc : IsColimit c
this : IsIso (Cofork.π c)
⊢ IsColimit (CokernelCofork.map c G)

Next tactic:
refine' IsColimit.ofIsoColimit (CokernelCofork.IsColimit.ofId _ (G.map_zero _ _)) _
noncomputable instance preservesCokernelZero :
    PreservesColimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := CokernelCofork.IsColimit.isIso_π c hc rfl
    refine' (CokernelCofork.isColimitMapCoconeEquiv c G).symm _
    refine' IsColimit.ofIsoColimit (CokernelCofork.IsColimit.ofId _ (G.map_zero _ _)) _
    

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cocone (parallelPair 0 0)
hc : IsColimit c
this : IsIso (Cofork.π c)
⊢ CokernelCofork.ofπ (𝟙 (G.obj Y)) (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 0) ≅ CokernelCofork.map c G

Next tactic:
exact (Cofork.ext (G.mapIso (asIso (Cofork.π c))) (by simp))
noncomputable instance preservesCokernelZero :
    PreservesColimit (parallelPair (0 : X ⟶ Y) 0) G where
  preserves {c} hc := by
    have := CokernelCofork.IsColimit.isIso_π c hc rfl
    refine' (CokernelCofork.isColimitMapCoconeEquiv c G).symm _
    refine' IsColimit.ofIsoColimit (CokernelCofork.IsColimit.ofId _ (G.map_zero _ _)) _
    exact (Cofork.ext (G.mapIso (asIso (Cofork.π c))) (by 

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
c : Cocone (parallelPair 0 0)
hc : IsColimit c
this : IsIso (Cofork.π c)
⊢ Cofork.π (CokernelCofork.ofπ (𝟙 (G.obj Y)) (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 0)) ≫ (G.mapIso (asIso (Cofork.π c))).hom =
    Cofork.π (CokernelCofork.map c G)

Next tactic:
simp
/-- The kernel of a zero map is preserved by any functor which preserves zero morphisms. -/
noncomputable def preservesKernelZero' (f : X ⟶ Y) (hf : f = 0) :
    PreservesLimit (parallelPair f 0) G := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
f : X ⟶ Y
hf : f = 0
⊢ PreservesLimit (parallelPair f 0) G

Next tactic:
rw [hf]
/-- The kernel of a zero map is preserved by any functor which preserves zero morphisms. -/
noncomputable def preservesKernelZero' (f : X ⟶ Y) (hf : f = 0) :
    PreservesLimit (parallelPair f 0) G := by
  rw [hf]
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
f : X ⟶ Y
hf : f = 0
⊢ PreservesLimit (parallelPair 0 0) G

Next tactic:
infer_instance
/-- The cokernel of a zero map is preserved by any functor which preserves zero morphisms. -/
noncomputable def preservesCokernelZero' (f : X ⟶ Y) (hf : f = 0) :
    PreservesColimit (parallelPair f 0) G := by
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
f : X ⟶ Y
hf : f = 0
⊢ PreservesColimit (parallelPair f 0) G

Next tactic:
rw [hf]
/-- The cokernel of a zero map is preserved by any functor which preserves zero morphisms. -/
noncomputable def preservesCokernelZero' (f : X ⟶ Y) (hf : f = 0) :
    PreservesColimit (parallelPair f 0) G := by
  rw [hf]
  

Proof state:
C : Type u₁
inst✝⁴ : Category.{v₁, u₁} C
inst✝³ : HasZeroMorphisms C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
inst✝¹ : HasZeroMorphisms D
X Y : C
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
f : X ⟶ Y
hf : f = 0
⊢ PreservesColimit (parallelPair 0 0) G

Next tactic:
infer_instance
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α α' : Sort u
β : α → Sort v
β' : α' → Sort v
f : (a : α) → β a
f' : (a : α') → β' a
hα : α = α'
h : ∀ (a : α) (a' : α'), HEq a a' → HEq (f a) (f' a')
⊢ HEq f f'

Next tactic:
subst hα
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f : (a : α) → β a
β' : α → Sort v
f' : (a : α) → β' a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
⊢ HEq f f'

Next tactic:
have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f : (a : α) → β a
β' : α → Sort v
f' : (a : α) → β' a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this : ∀ (a : α), HEq (f a) (f' a)
⊢ HEq f f'

Next tactic:
have : β = β' := by funext a
                      exact type_eq_of_heq (this a)
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  have : β = β' := by 

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f : (a : α) → β a
β' : α → Sort v
f' : (a : α) → β' a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this : ∀ (a : α), HEq (f a) (f' a)
⊢ β = β'

Next tactic:
funext a
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  have : β = β' := by funext a
                      

Proof state:
case h
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f : (a : α) → β a
β' : α → Sort v
f' : (a : α) → β' a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this : ∀ (a : α), HEq (f a) (f' a)
a : α
⊢ β a = β' a

Next tactic:
exact type_eq_of_heq (this a)
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  have : β = β' := by funext a
                      exact type_eq_of_heq (this a)
  

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f : (a : α) → β a
β' : α → Sort v
f' : (a : α) → β' a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this✝ : ∀ (a : α), HEq (f a) (f' a)
this : β = β'
⊢ HEq f f'

Next tactic:
subst this
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  have : β = β' := by funext a
                      exact type_eq_of_heq (this a)
  subst this
  

Proof state:
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f f' : (a : α) → β a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this : ∀ (a : α), HEq (f a) (f' a)
⊢ HEq f f'

Next tactic:
apply heq_of_eq
lemma hfunext {α α' : Sort u} {β : α → Sort v} {β' : α' → Sort v} {f : ∀a, β a} {f' : ∀a, β' a}
    (hα : α = α') (h : ∀a a', HEq a a' → HEq (f a) (f' a')) : HEq f f' := by
  subst hα
  have : ∀a, HEq (f a) (f' a) := λ a => h a a (HEq.refl a)
  have : β = β' := by funext a
                      exact type_eq_of_heq (this a)
  subst this
  apply heq_of_eq
  

Proof state:
case h
α✝ : Sort ?u.774
β✝ : Sort ?u.777
γ : Sort ?u.780
f✝ : α✝ → β✝
α : Sort u
β : α → Sort v
f f' : (a : α) → β a
h : ∀ (a a' : α), HEq a a' → HEq (f a) (f' a')
this : ∀ (a : α), HEq (f a) (f' a)
⊢ f = f'

Next tactic:
funext a