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 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 rw [← s.condition, Category.assoc]
  rcases PullbackCone.IsLimit.lift' H (s.fst ≫ g₁) s.snd this with ⟨l₁, hl₁, hl₁'⟩
  rcases PullbackCone.IsLimit.lift' H' s.fst l₁ hl₁.symm with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use hl₂
  use
    show l₂ ≫ f₁ ≫ f₂ = s.snd by
      rw [← hl₁', ← hl₂', Category.assoc]
      rfl
  intro m hm₁ hm₂
  apply PullbackCone.IsLimit.hom_ext H'
  · erw [hm₁, hl₂]
  · apply PullbackCone.IsLimit.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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
s : PullbackCone (g₁ ≫ g₂) i₃
this : (PullbackCone.fst s ≫ g₁) ≫ g₂ = PullbackCone.snd s ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₂ f₂ h₂).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.fst s ≫ g₁
hl₁' : l₁ ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.snd s
l₂ : s.pt ⟶ (PullbackCone.mk i₁ f₁ h₁).pt
hl₂ : l₂ ≫ PullbackCone.fst (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.fst s
hl₂' : l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = l₁
m : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hm₁ : m ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hm₂ : m ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s
⊢ (m ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂) =
    (l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂)

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 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 rw [← s.condition, Category.assoc]
  rcases PullbackCone.IsLimit.lift' H (s.fst ≫ g₁) s.snd this with ⟨l₁, hl₁, hl₁'⟩
  rcases PullbackCone.IsLimit.lift' H' s.fst l₁ hl₁.symm with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use hl₂
  use
    show l₂ ≫ f₁ ≫ f₂ = s.snd by
      rw [← hl₁', ← hl₂', Category.assoc]
      rfl
  intro m hm₁ hm₂
  apply PullbackCone.IsLimit.hom_ext H'
  · erw [hm₁, hl₂]
  · apply PullbackCone.IsLimit.hom_ext H
    · 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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
s : PullbackCone (g₁ ≫ g₂) i₃
this : (PullbackCone.fst s ≫ g₁) ≫ g₂ = PullbackCone.snd s ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₂ f₂ h₂).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.fst s ≫ g₁
hl₁' : l₁ ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.snd s
l₂ : s.pt ⟶ (PullbackCone.mk i₁ f₁ h₁).pt
hl₂ : l₂ ≫ PullbackCone.fst (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.fst s
hl₂' : l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = l₁
m : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hm₁ : m ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hm₂ : m ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s
⊢ l₂ ≫ f₁ ≫ i₂ = l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂)

Next tactic:
rfl
/-- 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 rw [← s.condition, Category.assoc]
  rcases PullbackCone.IsLimit.lift' H (s.fst ≫ g₁) s.snd this with ⟨l₁, hl₁, hl₁'⟩
  rcases PullbackCone.IsLimit.lift' H' s.fst l₁ hl₁.symm with ⟨l₂, hl₂, hl₂'⟩
  use l₂
  use hl₂
  use
    show l₂ ≫ f₁ ≫ f₂ = s.snd by
      rw [← hl₁', ← hl₂', Category.assoc]
      rfl
  intro m hm₁ hm₂
  apply PullbackCone.IsLimit.hom_ext H'
  · erw [hm₁, hl₂]
  · apply PullbackCone.IsLimit.hom_ext H
    · erw [Category.assoc, ← h₁, ← Category.assoc, hm₁, ← hl₂, Category.assoc, Category.assoc, h₁]
      rfl
    · 

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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ f₁ h₁)
s : PullbackCone (g₁ ≫ g₂) i₃
this : (PullbackCone.fst s ≫ g₁) ≫ g₂ = PullbackCone.snd s ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₂ f₂ h₂).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.fst s ≫ g₁
hl₁' : l₁ ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂) = PullbackCone.snd s
l₂ : s.pt ⟶ (PullbackCone.mk i₁ f₁ h₁).pt
hl₂ : l₂ ≫ PullbackCone.fst (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.fst s
hl₂' : l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = l₁
m : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hm₁ : m ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hm₂ : m ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s
⊢ (m ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂) =
    (l₂ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂)

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
          

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₁)
⊢ 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 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
  

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₁)
⊢ IsColimit (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))

Next tactic:
fapply PushoutCocone.isColimitAux'
/-- 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'
  

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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
⊢ (s : PushoutCocone i₁ (f₁ ≫ f₂)) →
    { l //
      PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l = PushoutCocone.inl 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:
intro s
/-- 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
  

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 : IsColimit (PushoutCocone.mk g₂ i₃ h₂)
H' : IsColimit (PushoutCocone.mk g₁ i₂ h₁)
s : PushoutCocone i₁ (f₁ ≫ f₂)
⊢ { l //
    PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l = PushoutCocone.inl 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:
have : i₁ ≫ s.inl = f₁ ≫ f₂ ≫ s.inr := 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 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 

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₂)
⊢ i₁ ≫ PushoutCocone.inl s = f₁ ≫ f₂ ≫ PushoutCocone.inr s

Next tactic:
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 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]
  

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 : 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.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l = PushoutCocone.inl 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:
rcases PushoutCocone.IsColimit.desc' H' s.inl (f₂ ≫ s.inr) this with ⟨l₁, 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₁'⟩
  

Proof state:
case create.mk.intro
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.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l = PushoutCocone.inl 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:
rcases PushoutCocone.IsColimit.desc' H l₁ s.inr hl₁' with ⟨l₂, 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₂'⟩
  

Proof state:
case create.mk.intro.mk.intro
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
⊢ { l //
    PushoutCocone.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l = PushoutCocone.inl 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 l₂
/-- 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₂
  

Proof state:
case property
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.inl (PushoutCocone.mk (g₁ ≫ g₂) i₃ (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) ≫ l₂ = PushoutCocone.inl 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
    show (g₁ ≫ g₂) ≫ l₂ = s.inl by
      rw [← hl₁, ← hl₂, Category.assoc]
      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
      

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 s

Next tactic:
rw [← hl₁, ← hl₂, Category.assoc]