l3lab/ntp-mathlib huggingface dataset:
instance pushout_inr_iso_of_right_factors_epi (f : X ⟶ Y) :
    IsIso (pushout.inr : _ ⟶ pushout h (h ≫ f)) := by
  convert (congrArg IsIso (show pushout.inr ≫ _ = _ from colimit.isoColimitCocone_ι_inv
    ⟨_, pushoutIsPushoutOfEpiComp (𝟙 _) f h⟩ WalkingSpan.right)).mp
    inferInstance
  · 

Proof state:
case h.e'_4.h.e'_6.h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso f✝
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
⊢ h = h ≫ 𝟙 X

Next tactic:
apply (Category.comp_id _).symm
instance pushout_inr_iso_of_right_factors_epi (f : X ⟶ Y) :
    IsIso (pushout.inr : _ ⟶ pushout h (h ≫ f)) := by
  convert (congrArg IsIso (show pushout.inr ≫ _ = _ from colimit.isoColimitCocone_ι_inv
    ⟨_, pushoutIsPushoutOfEpiComp (𝟙 _) f h⟩ WalkingSpan.right)).mp
    inferInstance
  · apply (Category.comp_id _).symm
  · 

Proof state:
case h.e'_5.e'_6.h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso f✝
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
e_3✝ : Y = (span (h ≫ 𝟙 X) (h ≫ f)).obj right
e_4✝ : pushout h (h ≫ f) = colimit (span (h ≫ 𝟙 X) (h ≫ f))
⊢ h = h ≫ 𝟙 X

Next tactic:
apply (Category.comp_id _).symm
/-- If `f : X ⟶ Z` is iso, then `Y ⨿[X] Z ≅ Y`. This is the explicit colimit cocone. -/
def pushoutCoconeOfRightIso : PushoutCocone f g :=
  PushoutCocone.mk (𝟙 _) (inv g ≫ f) <| by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ f ≫ 𝟙 Y = g ≫ inv g ≫ f

Next tactic:
simp
theorem pushoutCoconeOfRightIso_ι_app_none : (pushoutCoconeOfRightIso f g).ι.app none = f := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ (pushoutCoconeOfRightIso f g).ι.app none = f

Next tactic:
simp
/-- Verify that the constructed cocone is indeed a colimit. -/
def pushoutCoconeOfRightIsoIsLimit : IsColimit (pushoutCoconeOfRightIso f g) :=
  PushoutCocone.isColimitAux' _ fun s => ⟨s.inl, by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
s : PushoutCocone f g
⊢ PushoutCocone.inl (pushoutCoconeOfRightIso f g) ≫ PushoutCocone.inl s = PushoutCocone.inl s ∧
    PushoutCocone.inr (pushoutCoconeOfRightIso f g) ≫ PushoutCocone.inl s = PushoutCocone.inr s ∧
      ∀ {m : (pushoutCoconeOfRightIso f g).pt ⟶ s.pt},
        PushoutCocone.inl (pushoutCoconeOfRightIso f g) ≫ m = PushoutCocone.inl s →
          PushoutCocone.inr (pushoutCoconeOfRightIso f g) ≫ m = PushoutCocone.inr s → m = PushoutCocone.inl s

Next tactic:
simp [← s.condition]
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ IsIso pushout.inl

Next tactic:
refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by simp), by simp, _⟩⟩
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ f ≫ 𝟙 Y = g ≫ inv g ≫ f

Next tactic:
simp
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by simp), by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ pushout.inl ≫ pushout.desc (𝟙 Y) (inv g ≫ f) (_ : f ≫ 𝟙 Y = g ≫ inv g ≫ f) = 𝟙 Y

Next tactic:
simp
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by simp), by simp, _⟩⟩
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ pushout.desc (𝟙 Y) (inv g ≫ f) (_ : f ≫ 𝟙 Y = g ≫ inv g ≫ f) ≫ pushout.inl = 𝟙 (pushout f g)

Next tactic:
ext
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by simp), by simp, _⟩⟩
  ext
  · 

Proof state:
case h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ pushout.inl ≫ pushout.desc (𝟙 Y) (inv g ≫ f) (_ : f ≫ 𝟙 Y = g ≫ inv g ≫ f) ≫ pushout.inl =
    pushout.inl ≫ 𝟙 (pushout f g)

Next tactic:
simp [← pushout.condition]
instance pushout_inl_iso_of_right_iso : IsIso (pushout.inl : _ ⟶ pushout f g) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (inv g ≫ f) (by simp), by simp, _⟩⟩
  ext
  · simp [← pushout.condition]
  · 

Proof state:
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
g : X ⟶ Z
inst✝ : IsIso g
⊢ pushout.inr ≫ pushout.desc (𝟙 Y) (inv g ≫ f) (_ : f ≫ 𝟙 Y = g ≫ inv g ≫ f) ≫ pushout.inl =
    pushout.inr ≫ 𝟙 (pushout f g)

Next tactic:
simp [pushout.condition]
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
⊢ HasPushout (h ≫ f) h

Next tactic:
conv =>
    congr
    case g => rw [← Category.comp_id h]
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  conv =>
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
| HasPushout (h ≫ f) h

Next tactic:
congr
    case g => rw [← Category.comp_id h]
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  conv =>
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
| HasPushout (h ≫ f) h

Next tactic:
congr
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  conv =>
    congr
    

Proof state:
case f
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
| h ≫ f
case g
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
| h

Next tactic:
case g => rw [← Category.comp_id h]
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  conv =>
    congr
    case g => 

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
| h

Next tactic:
rw [← Category.comp_id h]
instance hasPushout_of_left_factors_epi (f : X ⟶ Y) : HasPushout (h ≫ f) h := by
  conv =>
    congr
    case g => rw [← Category.comp_id h]
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
⊢ HasPushout (h ≫ f) (h ≫ 𝟙 X)

Next tactic:
infer_instance
instance pushout_inl_iso_of_left_factors_epi (f : X ⟶ Y) :
    IsIso (pushout.inl : _ ⟶ pushout (h ≫ f) h) := by
  

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
⊢ IsIso pushout.inl

Next tactic:
convert (congrArg IsIso (show pushout.inl ≫ _ = _ from colimit.isoColimitCocone_ι_inv
    ⟨_, pushoutIsPushoutOfEpiComp f (𝟙 _) h⟩ WalkingSpan.left)).mp
        inferInstance
instance pushout_inl_iso_of_left_factors_epi (f : X ⟶ Y) :
    IsIso (pushout.inl : _ ⟶ pushout (h ≫ f) h) := by
  convert (congrArg IsIso (show pushout.inl ≫ _ = _ from colimit.isoColimitCocone_ι_inv
    ⟨_, pushoutIsPushoutOfEpiComp f (𝟙 _) h⟩ WalkingSpan.left)).mp
        inferInstance;
  · 

Proof state:
case h.e'_4.h.e'_7.h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
⊢ h = h ≫ 𝟙 X

Next tactic:
exact (Category.comp_id _).symm
instance pushout_inl_iso_of_left_factors_epi (f : X ⟶ Y) :
    IsIso (pushout.inl : _ ⟶ pushout (h ≫ f) h) := by
  convert (congrArg IsIso (show pushout.inl ≫ _ = _ from colimit.isoColimitCocone_ι_inv
    ⟨_, pushoutIsPushoutOfEpiComp f (𝟙 _) h⟩ WalkingSpan.left)).mp
        inferInstance;
  · exact (Category.comp_id _).symm
  · 

Proof state:
case h.e'_5.e'_7.h
C : Type u
inst✝³ : Category.{v, u} C
D : Type u₂
inst✝² : Category.{v₂, u₂} D
W X Y Z : C
f✝ : X ⟶ Y
g : X ⟶ Z
inst✝¹ : IsIso g
h : W ⟶ X
inst✝ : Epi h
f : X ⟶ Y
e_3✝ : Y = (span (h ≫ f) (h ≫ 𝟙 X)).obj left
e_4✝ : pushout (h ≫ f) h = colimit (span (h ≫ f) (h ≫ 𝟙 X))
⊢ h = h ≫ 𝟙 X

Next tactic:
exact (Category.comp_id _).symm
@[simp]
theorem pullbackSymmetry_hom_of_mono_eq [Mono f] : (pullbackSymmetry f f).hom = 𝟙 _ := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullbackSymmetry f f).hom = 𝟙 (pullback f f)

Next tactic:
ext
@[simp]
theorem pullbackSymmetry_hom_of_mono_eq [Mono f] : (pullbackSymmetry f f).hom = 𝟙 _ := by
  ext; 

Proof state:
case h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullbackSymmetry f f).hom ≫ pullback.fst = 𝟙 (pullback f f) ≫ pullback.fst
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullbackSymmetry f f).hom ≫ pullback.snd = 𝟙 (pullback f f) ≫ pullback.snd

Next tactic:
simp [fst_eq_snd_of_mono_eq]
@[simp]
theorem pullbackSymmetry_hom_of_mono_eq [Mono f] : (pullbackSymmetry f f).hom = 𝟙 _ := by
  ext; simp [fst_eq_snd_of_mono_eq]; 

Proof state:
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullbackSymmetry f f).hom ≫ pullback.snd = 𝟙 (pullback f f) ≫ pullback.snd

Next tactic:
simp [fst_eq_snd_of_mono_eq]
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ IsIso pullback.fst

Next tactic:
refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), _, by simp⟩⟩
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ 𝟙 X ≫ f = 𝟙 X ≫ f

Next tactic:
simp
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), _, by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ pullback.lift (𝟙 X) (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f) ≫ pullback.fst = 𝟙 X

Next tactic:
simp
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), _, by simp⟩⟩
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ pullback.fst ≫ pullback.lift (𝟙 X) (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f) = 𝟙 (pullback f f)

Next tactic:
ext
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), _, by simp⟩⟩
  ext
  · 

Proof state:
case h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullback.fst ≫ pullback.lift (𝟙 X) (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f)) ≫ pullback.fst = 𝟙 (pullback f f) ≫ pullback.fst

Next tactic:
simp
instance fst_iso_of_mono_eq [Mono f] : IsIso (pullback.fst : pullback f f ⟶ _) := by
  refine' ⟨⟨pullback.lift (𝟙 _) (𝟙 _) (by simp), _, by simp⟩⟩
  ext
  · simp
  · 

Proof state:
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ (pullback.fst ≫ pullback.lift (𝟙 X) (𝟙 X) (_ : 𝟙 X ≫ f = 𝟙 X ≫ f)) ≫ pullback.snd = 𝟙 (pullback f f) ≫ pullback.snd

Next tactic:
simp [fst_eq_snd_of_mono_eq]
instance snd_iso_of_mono_eq [Mono f] : IsIso (pullback.snd : pullback f f ⟶ _) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ IsIso pullback.snd

Next tactic:
rw [← fst_eq_snd_of_mono_eq]
instance snd_iso_of_mono_eq [Mono f] : IsIso (pullback.snd : pullback f f ⟶ _) := by
  rw [← fst_eq_snd_of_mono_eq]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Mono f
⊢ IsIso pullback.fst

Next tactic:
infer_instance
@[simp]
theorem pullback_symmetry_hom_of_epi_eq [Epi f] : (pushoutSymmetry f f).hom = 𝟙 _ := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ (pushoutSymmetry f f).hom = 𝟙 (pushout f f)

Next tactic:
ext
@[simp]
theorem pullback_symmetry_hom_of_epi_eq [Epi f] : (pushoutSymmetry f f).hom = 𝟙 _ := by
  ext <;> 

Proof state:
case h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.inl ≫ (pushoutSymmetry f f).hom = pushout.inl ≫ 𝟙 (pushout f f)

Next tactic:
simp [inl_eq_inr_of_epi_eq]
@[simp]
theorem pullback_symmetry_hom_of_epi_eq [Epi f] : (pushoutSymmetry f f).hom = 𝟙 _ := by
  ext <;> 

Proof state:
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.inr ≫ (pushoutSymmetry f f).hom = pushout.inr ≫ 𝟙 (pushout f f)

Next tactic:
simp [inl_eq_inr_of_epi_eq]
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ IsIso pushout.inl

Next tactic:
refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by simp, _⟩⟩
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ f ≫ 𝟙 Y = f ≫ 𝟙 Y

Next tactic:
simp
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.inl ≫ pushout.desc (𝟙 Y) (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y) = 𝟙 Y

Next tactic:
simp
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by simp, _⟩⟩
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.desc (𝟙 Y) (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y) ≫ pushout.inl = 𝟙 (pushout f f)

Next tactic:
apply pushout.hom_ext
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by simp, _⟩⟩
  apply pushout.hom_ext
  · 

Proof state:
case h₀
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.inl ≫ pushout.desc (𝟙 Y) (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y) ≫ pushout.inl = pushout.inl ≫ 𝟙 (pushout f f)

Next tactic:
simp
instance inl_iso_of_epi_eq [Epi f] : IsIso (pushout.inl : _ ⟶ pushout f f) := by
  refine' ⟨⟨pushout.desc (𝟙 _) (𝟙 _) (by simp), by simp, _⟩⟩
  apply pushout.hom_ext
  · simp
  · 

Proof state:
case h₁
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ pushout.inr ≫ pushout.desc (𝟙 Y) (𝟙 Y) (_ : f ≫ 𝟙 Y = f ≫ 𝟙 Y) ≫ pushout.inl = pushout.inr ≫ 𝟙 (pushout f f)

Next tactic:
simp [inl_eq_inr_of_epi_eq]
instance inr_iso_of_epi_eq [Epi f] : IsIso (pushout.inr : _ ⟶ pushout f f) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ IsIso pushout.inr

Next tactic:
rw [← inl_eq_inr_of_epi_eq]
instance inr_iso_of_epi_eq [Epi f] : IsIso (pushout.inr : _ ⟶ pushout f f) := by
  rw [← inl_eq_inr_of_epi_eq]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
D : Type u₂
inst✝¹ : Category.{v₂, u₂} D
W X Y Z : C
f : X ⟶ Y
inst✝ : Epi f
⊢ IsIso pushout.inl

Next tactic:
infer_instance
/-- Given

X₁ - f₁ -> X₂ - f₂ -> X₃
|          |          |
i₁         i₂         i₃
∨          ∨          ∨
Y₁ - g₁ -> Y₂ - g₂ -> Y₃

Then the big square is a pullback if both the small squares are.
-/
def bigSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' : IsLimit (PullbackCone.mk _ _ h₁)) :
    IsLimit
      (PullbackCone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Y₁ Y₂ Y₃ : C
f₁ : X₁ ⟶ X₂
f₂ : X₂ ⟶ X₃
g₁ : Y₁ ⟶ Y₂
g₂ : Y₂ ⟶ Y₃
i₁ : X₁ ⟶ Y₁
i₂ : X₂ ⟶ Y₂
i₃ : X₃ ⟶ Y₃
h₁ : i₁ ≫ g₁ = f₁ ≫ i₂
h₂ : i₂ ≫ g₂ = f₂ ≫ i₃
H : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
⊢ i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃

Next tactic:
rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc]
/-- Given

X₁ - f₁ -> X₂ - f₂ -> X₃
|          |          |
i₁         i₂         i₃
∨          ∨          ∨
Y₁ - g₁ -> Y₂ - g₂ -> Y₃

Then the big square is a pullback if both the small squares are.
-/
def bigSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' : IsLimit (PullbackCone.mk _ _ h₁)) :
    IsLimit
      (PullbackCone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Y₁ Y₂ Y₃ : C
f₁ : X₁ ⟶ X₂
f₂ : X₂ ⟶ X₃
g₁ : Y₁ ⟶ Y₂
g₂ : Y₂ ⟶ Y₃
i₁ : X₁ ⟶ Y₁
i₂ : X₂ ⟶ Y₂
i₃ : X₃ ⟶ Y₃
h₁ : i₁ ≫ g₁ = f₁ ≫ i₂
h₂ : i₂ ≫ g₂ = f₂ ≫ i₃
H : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
⊢ IsLimit (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))

Next tactic:
fapply PullbackCone.isLimitAux'
/-- Given

X₁ - f₁ -> X₂ - f₂ -> X₃
|          |          |
i₁         i₂         i₃
∨          ∨          ∨
Y₁ - g₁ -> Y₂ - g₂ -> Y₃

Then the big square is a pullback if both the small squares are.
-/
def bigSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' : IsLimit (PullbackCone.mk _ _ h₁)) :
    IsLimit
      (PullbackCone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PullbackCone.isLimitAux'
  

Proof state:
case create
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Y₁ Y₂ Y₃ : C
f₁ : X₁ ⟶ X₂
f₂ : X₂ ⟶ X₃
g₁ : Y₁ ⟶ Y₂
g₂ : Y₂ ⟶ Y₃
i₁ : X₁ ⟶ Y₁
i₂ : X₂ ⟶ Y₂
i₃ : X₃ ⟶ Y₃
h₁ : i₁ ≫ g₁ = f₁ ≫ i₂
h₂ : i₂ ≫ g₂ = f₂ ≫ i₃
H : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
⊢ (s : PullbackCone (g₁ ≫ g₂) i₃) →
    { l //
      l ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s ∧
        l ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ∧
          ∀ {m : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt},
            m ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) =
                PullbackCone.fst s →
              m ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) =
                  PullbackCone.snd s →
                m = l }

Next tactic:
intro s
/-- Given

X₁ - f₁ -> X₂ - f₂ -> X₃
|          |          |
i₁         i₂         i₃
∨          ∨          ∨
Y₁ - g₁ -> Y₂ - g₂ -> Y₃

Then the big square is a pullback if both the small squares are.
-/
def bigSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' : IsLimit (PullbackCone.mk _ _ h₁)) :
    IsLimit
      (PullbackCone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PullbackCone.isLimitAux'
  intro s
  

Proof state:
case create
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Y₁ Y₂ Y₃ : C
f₁ : X₁ ⟶ X₂
f₂ : X₂ ⟶ X₃
g₁ : Y₁ ⟶ Y₂
g₂ : Y₂ ⟶ Y₃
i₁ : X₁ ⟶ Y₁
i₂ : X₂ ⟶ Y₂
i₃ : X₃ ⟶ Y₃
h₁ : i₁ ≫ g₁ = f₁ ≫ i₂
h₂ : i₂ ≫ g₂ = f₂ ≫ i₃
H : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
s : PullbackCone (g₁ ≫ g₂) i₃
⊢ { l //
    l ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s ∧
      l ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ∧
        ∀ {m : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt},
          m ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s →
            m ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) =
                PullbackCone.snd s →
              m = l }

Next tactic:
have : (s.fst ≫ g₁) ≫ g₂ = s.snd ≫ i₃ := by rw [← s.condition, Category.assoc]
/-- Given

X₁ - f₁ -> X₂ - f₂ -> X₃
|          |          |
i₁         i₂         i₃
∨          ∨          ∨
Y₁ - g₁ -> Y₂ - g₂ -> Y₃

Then the big square is a pullback if both the small squares are.
-/
def bigSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' : IsLimit (PullbackCone.mk _ _ h₁)) :
    IsLimit
      (PullbackCone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PullbackCone.isLimitAux'
  intro s
  have : (s.fst ≫ g₁) ≫ g₂ = s.snd ≫ i₃ := by 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u₂
inst✝ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Y₁ Y₂ Y₃ : C
f₁ : X₁ ⟶ X₂
f₂ : X₂ ⟶ X₃
g₁ : Y₁ ⟶ Y₂
g₂ : Y₂ ⟶ Y₃
i₁ : X₁ ⟶ Y₁
i₂ : X₂ ⟶ Y₂
i₃ : X₃ ⟶ Y₃
h₁ : i₁ ≫ g₁ = f₁ ≫ i₂
h₂ : i₂ ≫ g₂ = f₂ ≫ i₃
H : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
s : PullbackCone (g₁ ≫ g₂) i₃
⊢ (PullbackCone.fst s ≫ g₁) ≫ g₂ = PullbackCone.snd s ≫ i₃

Next tactic:
rw [← s.condition, Category.assoc]