l3lab/ntp-mathlib huggingface dataset:
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      

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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
⊢ g₁ ≫ g₂ ≫ l₂ = PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂

Next tactic:
rfl
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  

Proof state:
case right
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
⊢ PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l₂ = PushoutCocone.inr s ∧
    ∀ {m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt},
      PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s →
        PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m =
            PushoutCocone.inr s →
          m = l₂

Next tactic:
use hl₂'
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  

Proof state:
case right
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
⊢ ∀ {m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt},
    PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s →
      PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s →
        m = l₂

Next tactic:
intro m hm₁ hm₂
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  

Proof state:
case right
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ m = l₂

Next tactic:
apply PushoutCocone.IsColimit.hom_ext H
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  apply PushoutCocone.IsColimit.hom_ext H
  · 

Proof state:
case right.h₀
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ m = PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂

Next tactic:
apply PushoutCocone.IsColimit.hom_ext H'
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  apply PushoutCocone.IsColimit.hom_ext H
  · apply PushoutCocone.IsColimit.hom_ext H'
    · 

Proof state:
case right.h₀.h₀
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ m =
    PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂

Next tactic:
erw [← Category.assoc, hm₁, hl₂, hl₁]
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  apply PushoutCocone.IsColimit.hom_ext H
  · apply PushoutCocone.IsColimit.hom_ext H'
    · erw [← Category.assoc, hm₁, hl₂, hl₁]
    · 

Proof state:
case right.h₀.h₁
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ m =
    PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂

Next tactic:
erw [← Category.assoc, h₂, Category.assoc, hm₂, ← hl₂', ← Category.assoc, ← Category.assoc, ←
        h₂]
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  apply PushoutCocone.IsColimit.hom_ext H
  · apply PushoutCocone.IsColimit.hom_ext H'
    · erw [← Category.assoc, hm₁, hl₂, hl₁]
    · erw [← Category.assoc, h₂, Category.assoc, hm₂, ← hl₂', ← Category.assoc, ← Category.assoc, ←
        h₂]
      

Proof state:
case right.h₀.h₁
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ (i₂ ≫ g₂) ≫ l₂ = (PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂)) ≫ l₂

Next tactic:
rfl
/-- Given

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

Then the big square is a pushout if both the small squares are.
-/
def bigSquareIsPushout (H : IsColimit (PushoutCocone.mk _ _ h₂))
    (H' : IsColimit (PushoutCocone.mk _ _ h₁)) :
    IsColimit
      (PushoutCocone.mk _ _
        (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
          rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc])) := by
  fapply PushoutCocone.isColimitAux'
  intro s
  have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := by rw [s.condition, Category.assoc]
  rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, hl₁, hl₁'⟩
  rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      rfl
  use hl₂'
  intro m hm₁ hm₂
  apply PushoutCocone.IsColimit.hom_ext H
  · apply PushoutCocone.IsColimit.hom_ext H'
    · erw [← Category.assoc, hm₁, hl₂, hl₁]
    · erw [← Category.assoc, h₂, Category.assoc, hm₂, ← hl₂', ← Category.assoc, ← Category.assoc, ←
        h₂]
      rfl
  · 

Proof state:
case right.h₁
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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
this : i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s
l₁ : (PushoutCocone.mk g₁ i₂ h₁).pt ⟶ s.pt
hl₁ : PushoutCocone.inl (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = PushoutCocone.inl s
hl₁' : PushoutCocone.inr (PushoutCocone.mk g₁ i₂ h₁) ≫ l₁ = f₂ ≫ PushoutCocone.inr s
l₂ : (PushoutCocone.mk g₂ i₃ h₂).pt ⟶ s.pt
hl₂ : PushoutCocone.inl (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = l₁
hl₂' : PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂ = PushoutCocone.inr s
m : (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt ⟶ s.pt
hm₁ : PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inl s
hm₂ : PushoutCocone.inr (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ m = PushoutCocone.inr s
⊢ PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ m = PushoutCocone.inr (PushoutCocone.mk g₂ i₃ h₂) ≫ l₂

Next tactic:
erw [hm₂, hl₂']
/-- Given

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

Then the left square is a pullback if the right square and the big square are.
-/
def leftSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (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₂)
⊢ 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 left square is a pullback if the right square and the big square are.
-/
def leftSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' :
      IsLimit
        (PullbackCone.mk _ _
          (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
            rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc]))) :
    IsLimit (PullbackCone.mk _ _ h₁) := 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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
⊢ IsLimit (PullbackCone.mk i₁ f₁ h₁)

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

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

Then the left square is a pullback if the right square and the big square are.
-/
def leftSquareIsPullback (H : IsLimit (PullbackCone.mk _ _ h₂))
    (H' :
      IsLimit
        (PullbackCone.mk _ _
          (show i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃ by
            rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc]))) :
    IsLimit (PullbackCone.mk _ _ h₁) := 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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
⊢ (s : PullbackCone g₁ i₂) →
    { l //
      l ≫ PullbackCone.fst (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.fst s ∧
        l ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.snd s ∧
          ∀ {m : s.pt ⟶ (PullbackCone.mk i₁ f₁ h₁).pt},
            m ≫ PullbackCone.fst (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.fst s →
              m ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.snd s → m = l }

Next tactic:
intro s