l3lab/ntp-mathlib huggingface dataset:
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> 

Proof state:
case refine'_1.refine'_2
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 : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ (parallelPair f 0 ⋙ G).map WalkingParallelPairHom.right ≫
      (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one)).hom =
    (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero)).hom ≫
      (parallelPair (G.map f) 0).map WalkingParallelPairHom.right

Next tactic:
simp
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> simp
  

Proof state:
case refine'_2
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 : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ (Cones.postcompose
          (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
              (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
              (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
              (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
      (G.mapCone c) ≅
    map c G

Next tactic:
exact Cones.ext (Iso.refl _) (by rintro (_|_) <;> aesop_cat)
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> simp
  exact Cones.ext (Iso.refl _) (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
f : X ⟶ Y
c : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ ∀ (j : WalkingParallelPair),
    ((Cones.postcompose
                  (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                      (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                      (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                      (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
              (G.mapCone c)).π.app
        j =
      (Iso.refl
            ((Cones.postcompose
                    (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                        (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                        (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                        (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
                (G.mapCone c)).pt).hom ≫
        (map c G).π.app j

Next tactic:
rintro (_|_)
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> simp
  exact Cones.ext (Iso.refl _) (by rintro (_|_) <;> 

Proof state:
case zero
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 : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ ((Cones.postcompose
                (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                    (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                    (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                    (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
            (G.mapCone c)).π.app
      WalkingParallelPair.zero =
    (Iso.refl
          ((Cones.postcompose
                  (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                      (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                      (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                      (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
              (G.mapCone c)).pt).hom ≫
      (map c G).π.app WalkingParallelPair.zero

Next tactic:
aesop_cat
/-- The underlying cone of a kernel fork is mapped to a limit cone if and only if
the mapped kernel fork is limit. -/
def isLimitMapConeEquiv :
    IsLimit (G.mapCone c) ≃ IsLimit (c.map G) := by
  refine' (IsLimit.postcomposeHomEquiv _ _).symm.trans (IsLimit.equivIsoLimit _)
  refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _ <;> simp
  exact Cones.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 : KernelFork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ ((Cones.postcompose
                (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                    (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                    (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                    (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
            (G.mapCone c)).π.app
      WalkingParallelPair.one =
    (Iso.refl
          ((Cones.postcompose
                  (parallelPair.ext (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.zero))
                      (Iso.refl ((parallelPair f 0 ⋙ G).obj WalkingParallelPair.one))
                      (_ : G.map f ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ G.map f)
                      (_ : G.map 0 ≫ 𝟙 (G.obj Y) = 𝟙 (G.obj X) ≫ 0)).hom).obj
              (G.mapCone c)).pt).hom ≫
      (map c G).π.app WalkingParallelPair.one

Next tactic:
aesop_cat
/-- The map of a kernel fork is a limit iff
the kernel fork consisting of the mapped morphisms is a limit.
This essentially lets us commute `KernelFork.ofι` with `Functor.mapCone`.

This is a variant of `isLimitMapConeForkEquiv` for equalizers,
which we can't use directly between `G.map 0 = 0` does not hold definitionally.
-/
def isLimitMapConeForkEquiv' :
    IsLimit (G.mapCone (KernelFork.ofι h w)) ≃
      IsLimit
        (KernelFork.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 : Z ⟶ X
w : h ≫ f = 0
⊢ G.map h ≫ G.map f = 0

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

This is a variant of `isLimitForkMapOfIsLimit` for equalizers,
which we can't use directly between `G.map 0 = 0` does not hold definitionally.
-/
def isLimitForkMapOfIsLimit' [PreservesLimit (parallelPair f 0) G]
    (l : IsLimit (KernelFork.ofι h w)) :
    IsLimit
      (KernelFork.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 : Z ⟶ X
w : h ≫ f = 0
inst✝ : PreservesLimit (parallelPair f 0) G
l : IsLimit (KernelFork.ofι h w)
⊢ G.map h ≫ G.map f = 0

Next tactic:
simp only [← G.map_comp, w, Functor.map_zero]
/-- If `G` preserves kernels and `C` has them, then the fork constructed of the mapped morphisms of
a kernel fork is a limit.
-/
def isLimitOfHasKernelOfPreservesLimit [PreservesLimit (parallelPair f 0) G] :
    IsLimit
      (Fork.ofι (G.map (kernel.ι 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 : Z ⟶ X
w : h ≫ f = 0
inst✝¹ : HasKernel f
inst✝ : PreservesLimit (parallelPair f 0) G
⊢ G.map (kernel.ι f) ≫ G.map f = G.map (kernel.ι f) ≫ 0

Next tactic:
simp only [← G.map_comp, kernel.condition, comp_zero, Functor.map_zero]
/-- If the kernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
kernel of `f`.
-/
def PreservesKernel.ofIsoComparison [i : IsIso (kernelComparison f G)] :
    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
G : C ⥤ D
inst✝² : Functor.PreservesZeroMorphisms G
X Y Z : C
f : X ⟶ Y
h : Z ⟶ X
w : h ≫ f = 0
inst✝¹ : HasKernel f
inst✝ : HasKernel (G.map f)
i : IsIso (kernelComparison f G)
⊢ PreservesLimit (parallelPair f 0) G

Next tactic:
apply preservesLimitOfPreservesLimitCone (kernelIsKernel f)
/-- If the kernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
kernel of `f`.
-/
def PreservesKernel.ofIsoComparison [i : IsIso (kernelComparison f G)] :
    PreservesLimit (parallelPair f 0) G := by
  apply preservesLimitOfPreservesLimitCone (kernelIsKernel 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 : Z ⟶ X
w : h ≫ f = 0
inst✝¹ : HasKernel f
inst✝ : HasKernel (G.map f)
i : IsIso (kernelComparison f G)
⊢ IsLimit (G.mapCone (Fork.ofι (kernel.ι f) (_ : kernel.ι f ≫ f = kernel.ι f ≫ 0)))

Next tactic:
apply (isLimitMapConeForkEquiv' G (kernel.condition f)).symm _
/-- If the kernel comparison map for `G` at `f` is an isomorphism, then `G` preserves the
kernel of `f`.
-/
def PreservesKernel.ofIsoComparison [i : IsIso (kernelComparison f G)] :
    PreservesLimit (parallelPair f 0) G := by
  apply preservesLimitOfPreservesLimitCone (kernelIsKernel f)
  apply (isLimitMapConeForkEquiv' G (kernel.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 : Z ⟶ X
w : h ≫ f = 0
inst✝¹ : HasKernel f
inst✝ : HasKernel (G.map f)
i : IsIso (kernelComparison f G)
⊢ IsLimit (KernelFork.ofι (G.map (kernel.ι f)) (_ : G.map (kernel.ι f) ≫ G.map f = 0))

Next tactic:
exact @IsLimit.ofPointIso _ _ _ _ _ _ _ (kernelIsKernel (G.map f)) i
@[simp]
theorem PreservesKernel.iso_hom : (PreservesKernel.iso G f).hom = kernelComparison 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 : Z ⟶ X
w : h ≫ f = 0
inst✝² : HasKernel f
inst✝¹ : HasKernel (G.map f)
inst✝ : PreservesLimit (parallelPair f 0) G
⊢ (iso G f).hom = kernelComparison f G

Next tactic:
rw [← cancel_mono (kernel.ι _)]
@[simp]
theorem PreservesKernel.iso_hom : (PreservesKernel.iso G f).hom = kernelComparison f G := by
  rw [← cancel_mono (kernel.ι _)]
  

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 : Z ⟶ X
w : h ≫ f = 0
inst✝² : HasKernel f
inst✝¹ : HasKernel (G.map f)
inst✝ : PreservesLimit (parallelPair f 0) G
⊢ (iso G f).hom ≫ kernel.ι (G.map f) = kernelComparison f G ≫ kernel.ι (G.map f)

Next tactic:
simp [PreservesKernel.iso]
instance : IsIso (kernelComparison 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 : Z ⟶ X
w : h ≫ f = 0
inst✝² : HasKernel f
inst✝¹ : HasKernel (G.map f)
inst✝ : PreservesLimit (parallelPair f 0) G
⊢ IsIso (kernelComparison f G)

Next tactic:
rw [← PreservesKernel.iso_hom]
instance : IsIso (kernelComparison f G) := by
  rw [← PreservesKernel.iso_hom]
  

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 : Z ⟶ X
w : h ≫ f = 0
inst✝² : HasKernel f
inst✝¹ : HasKernel (G.map f)
inst✝ : PreservesLimit (parallelPair f 0) G
⊢ IsIso (PreservesKernel.iso G f).hom

Next tactic:
infer_instance
@[reassoc]
theorem kernel_map_comp_preserves_kernel_iso_inv {X' Y' : C} (g : X' ⟶ Y') [HasKernel g]
    [HasKernel (G.map g)] [PreservesLimit (parallelPair g 0) G] (p : X ⟶ X') (q : Y ⟶ Y')
    (hpq : f ≫ q = p ≫ g) :
    kernel.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 : Z ⟶ X
w : h ≫ f = 0
inst✝⁵ : HasKernel f
inst✝⁴ : HasKernel (G.map f)
inst✝³ : PreservesLimit (parallelPair f 0) G
X' Y' : C
g : X' ⟶ Y'
inst✝² : HasKernel g
inst✝¹ : HasKernel (G.map g)
inst✝ : PreservesLimit (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 kernel_map_comp_preserves_kernel_iso_inv {X' Y' : C} (g : X' ⟶ Y') [HasKernel g]
    [HasKernel (G.map g)] [PreservesLimit (parallelPair g 0) G] (p : X ⟶ X') (q : Y ⟶ Y')
    (hpq : f ≫ q = p ≫ g) :
    kernel.map (G.map f) (G.map g) (G.map p) (G.map q) (by rw [← G.map_comp, hpq, G.map_comp]) ≫
        (PreservesKernel.iso G _).inv =
      (PreservesKernel.iso G _).inv ≫ G.map (kernel.map f g p q hpq) := 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 : Z ⟶ X
w : h ≫ f = 0
inst✝⁵ : HasKernel f
inst✝⁴ : HasKernel (G.map f)
inst✝³ : PreservesLimit (parallelPair f 0) G
X' Y' : C
g : X' ⟶ Y'
inst✝² : HasKernel g
inst✝¹ : HasKernel (G.map g)
inst✝ : PreservesLimit (parallelPair g 0) G
p : X ⟶ X'
q : Y ⟶ Y'
hpq : f ≫ q = p ≫ g
⊢ kernel.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) ≫
      (PreservesKernel.iso G g).inv =
    (PreservesKernel.iso G f).inv ≫ G.map (kernel.map f g p q hpq)

Next tactic:
rw [Iso.comp_inv_eq, Category.assoc, PreservesKernel.iso_hom, Iso.eq_inv_comp,
    PreservesKernel.iso_hom, kernelComparison_comp_kernel_map]
@[reassoc (attr := simp)]
lemma map_condition : G.map f ≫ G.map c.π = 0 := 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
f : X ⟶ Y
c : CokernelCofork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ G.map f ≫ G.map (Cofork.π c) = 0

Next tactic:
rw [← G.map_comp, c.condition, G.map_zero]
/-- 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
  

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
f : X ⟶ Y
c : CokernelCofork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ IsColimit (G.mapCocone c) ≃ IsColimit (map c G)

Next tactic:
refine' (IsColimit.precomposeHomEquiv _ _).symm.trans (IsColimit.equivIsoColimit _)
/-- 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 _)
  

Proof state:
case refine'_1
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
⊢ parallelPair (G.map f) 0 ≅ parallelPair f 0 ⋙ G

Next tactic:
refine' parallelPair.ext (Iso.refl _) (Iso.refl _) _ _
/-- 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 _) _ _ <;> 

Proof state:
case refine'_1.refine'_1
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
⊢ (parallelPair (G.map f) 0).map WalkingParallelPairHom.left ≫
      (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.one)).hom =
    (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.zero)).hom ≫
      (parallelPair f 0 ⋙ G).map WalkingParallelPairHom.left

Next tactic:
simp
/-- 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 _) _ _ <;> 

Proof state:
case refine'_1.refine'_2
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
⊢ (parallelPair (G.map f) 0).map WalkingParallelPairHom.right ≫
      (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.one)).hom =
    (Iso.refl ((parallelPair (G.map f) 0).obj WalkingParallelPair.zero)).hom ≫
      (parallelPair f 0 ⋙ G).map WalkingParallelPairHom.right

Next tactic:
simp
/-- 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
  

Proof state:
case refine'_2
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) ≅
    map c G

Next tactic:
exact Cocones.ext (Iso.refl _) (by rintro (_|_) <;> aesop_cat)
/-- 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 

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
f : X ⟶ Y
c : CokernelCofork f
G : C ⥤ D
inst✝ : Functor.PreservesZeroMorphisms G
⊢ ∀ (j : WalkingParallelPair),
    ((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
          j ≫
        (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 j

Next tactic:
rintro (_|_)
/-- 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 zero
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.zero ≫
      (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.zero

Next tactic:
aesop_cat