l3lab/ntp-mathlib huggingface dataset:
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutLeftIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk l₁' l₂' (show f₂ ≫ l₁' = f₃ ≫ l₂' from (pushout.inl_desc _ _ _).symm)) := by
  apply PushoutCocone.flipIsColimit
  apply rightSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · 

Proof state:
case t.H'
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ IsColimit
    (PushoutCocone.mk
      (pushout.inr ≫
        pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr))
      pushout.inl
      (_ :
        g₄ ≫
            pushout.inr ≫
              pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr
                (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr) =
          (g₃ ≫ pushout.inr) ≫ pushout.inl))

Next tactic:
apply PushoutCocone.flipIsColimit
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutLeftIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk l₁' l₂' (show f₂ ≫ l₁' = f₃ ≫ l₂' from (pushout.inl_desc _ _ _).symm)) := by
  apply PushoutCocone.flipIsColimit
  apply rightSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · apply PushoutCocone.flipIsColimit
    

Proof state:
case t.H'.t
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ IsColimit
    (PushoutCocone.mk pushout.inl
      (pushout.inr ≫
        pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr))
      (_ :
        (g₃ ≫ pushout.inr) ≫ pushout.inl =
          g₄ ≫
            pushout.inr ≫
              pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr
                (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr)))

Next tactic:
convert pushoutIsPushout (g₃ ≫ f₂) g₄
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutLeftIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk l₁' l₂' (show f₂ ≫ l₁' = f₃ ≫ l₂' from (pushout.inl_desc _ _ _).symm)) := by
  apply PushoutCocone.flipIsColimit
  apply rightSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · apply PushoutCocone.flipIsColimit
    convert pushoutIsPushout (g₃ ≫ f₂) g₄
    

Proof state:
case h.e'_6.h.e'_10
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ pushout.inr ≫
      pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr) =
    pushout.inr

Next tactic:
exact pushout.inr_desc _ _ _
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutLeftIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk l₁' l₂' (show f₂ ≫ l₁' = f₃ ≫ l₂' from (pushout.inl_desc _ _ _).symm)) := by
  apply PushoutCocone.flipIsColimit
  apply rightSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · apply PushoutCocone.flipIsColimit
    convert pushoutIsPushout (g₃ ≫ f₂) g₄
    exact pushout.inr_desc _ _ _
  · 

Proof state:
case t.h₁
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ g₄ ≫ pushout.inr = g₃ ≫ pushout.inl

Next tactic:
exact pushout.condition.symm
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutAssocIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk (f₁ ≫ l₁') l₂'
        (show g₁ ≫ f₁ ≫ l₁' = (g₂ ≫ f₃) ≫ l₂' 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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ g₁ ≫ pushout.inl ≫ pushout.inl =
    (g₂ ≫ pushout.inl) ≫
      pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr)

Next tactic:
rw [Category.assoc, pushout.inl_desc, pushout.condition_assoc]
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutAssocIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk (f₁ ≫ l₁') l₂'
        (show g₁ ≫ f₁ ≫ l₁' = (g₂ ≫ f₃) ≫ l₂' by
          rw [Category.assoc, pushout.inl_desc, pushout.condition_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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ IsColimit
    (PushoutCocone.mk (pushout.inl ≫ pushout.inl)
      (pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr))
      (_ :
        g₁ ≫ pushout.inl ≫ pushout.inl =
          (g₂ ≫ pushout.inl) ≫
            pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr
              (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr)))

Next tactic:
apply bigSquareIsPushout
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutAssocIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk (f₁ ≫ l₁') l₂'
        (show g₁ ≫ f₁ ≫ l₁' = (g₂ ≫ f₃) ≫ l₂' by
          rw [Category.assoc, pushout.inl_desc, pushout.condition_assoc])) := by
  apply bigSquareIsPushout
  · 

Proof state:
case H
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ IsColimit
    (PushoutCocone.mk pushout.inl
      (pushout.desc (pushout.inr ≫ pushout.inl) pushout.inr (_ : g₃ ≫ pushout.inr ≫ pushout.inl = g₄ ≫ pushout.inr))
      ?h₂)

Next tactic:
apply pushoutPushoutLeftIsPushout
/-- `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃` is the pushout `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutAssocIsPushout [HasPushout (g₃ ≫ f₂) g₄] :
    IsColimit
      (PushoutCocone.mk (f₁ ≫ l₁') l₂'
        (show g₁ ≫ f₁ ≫ l₁' = (g₂ ≫ f₃) ≫ l₂' by
          rw [Category.assoc, pushout.inl_desc, pushout.condition_assoc])) := by
  apply bigSquareIsPushout
  · apply pushoutPushoutLeftIsPushout
  · 

Proof state:
case H'
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout (g₃ ≫ pushout.inr) g₄
⊢ IsColimit (PushoutCocone.mk pushout.inl pushout.inr ?h₁)

Next tactic:
exact pushoutIsPushout _ _
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutRightIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit (PushoutCocone.mk l₁ l₂ (show f₂ ≫ l₁ = f₃ ≫ l₂ from pushout.inr_desc _ _ _)) := 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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk
      (pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      pushout.inr
      (_ :
        pushout.inr ≫
            pushout.desc pushout.inl (pushout.inl ≫ pushout.inr)
              (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
          pushout.inl ≫ pushout.inr))

Next tactic:
apply rightSquareIsPushout
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutRightIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit (PushoutCocone.mk l₁ l₂ (show f₂ ≫ l₁ = f₃ ≫ l₂ from pushout.inr_desc _ _ _)) := by
  apply rightSquareIsPushout
  · 

Proof state:
case H
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit (PushoutCocone.mk ?g₁ pushout.inr ?h₁)

Next tactic:
exact pushoutIsPushout _ _
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutRightIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit (PushoutCocone.mk l₁ l₂ (show f₂ ≫ l₁ = f₃ ≫ l₂ from pushout.inr_desc _ _ _)) := by
  apply rightSquareIsPushout
  · exact pushoutIsPushout _ _
  · 

Proof state:
case H'
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk
      (pushout.inl ≫
        pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      pushout.inr
      (_ :
        g₁ ≫
            pushout.inl ≫
              pushout.desc pushout.inl (pushout.inl ≫ pushout.inr)
                (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
          (g₂ ≫ pushout.inl) ≫ pushout.inr))

Next tactic:
convert pushoutIsPushout g₁ (g₂ ≫ f₃)
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ×[X₂] (X₂ ⨿[Z₂] X₃)`. -/
def pushoutPushoutRightIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit (PushoutCocone.mk l₁ l₂ (show f₂ ≫ l₁ = f₃ ≫ l₂ from pushout.inr_desc _ _ _)) := by
  apply rightSquareIsPushout
  · exact pushoutIsPushout _ _
  · convert pushoutIsPushout g₁ (g₂ ≫ f₃)
    

Proof state:
case h.e'_6.h.e'_9
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
    pushout.inl

Next tactic:
rw [pushout.inl_desc]
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ 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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ (g₃ ≫ pushout.inr) ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
    g₄ ≫ pushout.inr ≫ pushout.inr

Next tactic:
rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc]
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk
      (pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      (pushout.inr ≫ pushout.inr)
      (_ :
        (g₃ ≫ pushout.inr) ≫
            pushout.desc pushout.inl (pushout.inl ≫ pushout.inr)
              (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
          g₄ ≫ pushout.inr ≫ pushout.inr))

Next tactic:
apply PushoutCocone.flipIsColimit
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  

Proof state:
case t
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk (pushout.inr ≫ pushout.inr)
      (pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      (_ :
        g₄ ≫ pushout.inr ≫ pushout.inr =
          (g₃ ≫ pushout.inr) ≫
            pushout.desc pushout.inl (pushout.inl ≫ pushout.inr)
              (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)))

Next tactic:
apply bigSquareIsPushout
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · 

Proof state:
case t.H
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk pushout.inr
      (pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      ?t.h₂)

Next tactic:
apply PushoutCocone.flipIsColimit
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    

Proof state:
case t.H.t
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit
    (PushoutCocone.mk
      (pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr))
      pushout.inr
      (_ :
        pushout.inr ≫
            pushout.desc pushout.inl (pushout.inl ≫ pushout.inr)
              (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
          ?t.i₂ ≫ pushout.inr))

Next tactic:
apply pushoutPushoutRightIsPushout
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    apply pushoutPushoutRightIsPushout
  · 

Proof state:
case t.H'
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit (PushoutCocone.mk pushout.inr pushout.inl ?t.h₁)

Next tactic:
apply PushoutCocone.flipIsColimit
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    apply pushoutPushoutRightIsPushout
  · apply PushoutCocone.flipIsColimit
    

Proof state:
case t.H'.t
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ IsColimit (PushoutCocone.mk pushout.inl pushout.inr (_ : g₃ ≫ pushout.inl = g₄ ≫ pushout.inr))

Next tactic:
exact pushoutIsPushout _ _
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    apply pushoutPushoutRightIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · 

Proof state:
case t.h₁
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ g₄ ≫ pushout.inr = g₃ ≫ pushout.inl

Next tactic:
exact pushout.condition.symm
/-- `X₁ ⨿[Z₁] (X₂ ⨿[Z₂] X₃)` is the pushout `(X₁ ⨿[Z₁] X₂) ⨿[Z₂] X₃`. -/
def pushoutAssocSymmIsPushout [HasPushout g₁ (g₂ ≫ f₃)] :
    IsColimit
      (PushoutCocone.mk l₁ (f₄ ≫ l₂)
        (show (g₃ ≫ f₂) ≫ l₁ = g₄ ≫ f₄ ≫ l₂ by
          rw [Category.assoc, pushout.inr_desc, pushout.condition_assoc])) := by
  apply PushoutCocone.flipIsColimit
  apply bigSquareIsPushout
  · apply PushoutCocone.flipIsColimit
    apply pushoutPushoutRightIsPushout
  · apply PushoutCocone.flipIsColimit
    exact pushoutIsPushout _ _
  · exact pushout.condition.symm
  · 

Proof state:
case t.h₂
C : Type u
inst✝⁴ : Category.{v, u} C
D : Type u₂
inst✝³ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝² : HasPushout g₁ g₂
inst✝¹ : HasPushout g₃ g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ pushout.inr =
    pushout.inr ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)

Next tactic:
exact (pushout.inr_desc _ _ _).symm
@[reassoc (attr := simp)]
theorem inl_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl

Next tactic:
trans f₁ ≫ l₁
@[reassoc (attr := simp)]
theorem inl_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl := by
  trans f₁ ≫ l₁
  · 

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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom =
    pushout.inl ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)

Next tactic:
congr 1
@[reassoc (attr := simp)]
theorem inl_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl := by
  trans f₁ ≫ l₁
  · congr 1
    

Proof state:
case e_a
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u₂
inst✝⁴ : Category.{v₂, u₂} D
W X Y Z X₁ X₂ X₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom =
    pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)

Next tactic:
exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_hom _
        WalkingCospan.left
@[reassoc (attr := simp)]
theorem inl_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inl ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl := by
  trans f₁ ≫ l₁
  · congr 1
    exact
      (pushoutPushoutLeftIsPushout g₁ g₂ g₃ g₄).comp_coconePointUniqueUpToIso_hom _
        WalkingCospan.left
  · 

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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inl ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr) =
    pushout.inl

Next tactic:
exact pushout.inl_desc _ _ _
@[reassoc (attr := simp)]
theorem inr_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl ≫ pushout.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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl ≫ pushout.inr

Next tactic:
trans f₂ ≫ l₁
@[reassoc (attr := simp)]
theorem inr_inl_pushoutAssoc_hom [HasPushout (g₃ ≫ (pushout.inr : X₂ ⟶ Y₁)) g₄]
    [HasPushout g₁ (g₂ ≫ (pushout.inl : X₂ ⟶ Y₂))] :
    pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom = pushout.inl ≫ pushout.inr := by
  trans f₂ ≫ l₁
  · 

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₃ Z₁ Z₂ : C
g₁ : Z₁ ⟶ X₁
g₂ : Z₁ ⟶ X₂
g₃ : Z₂ ⟶ X₂
g₄ : Z₂ ⟶ X₃
inst✝³ : HasPushout g₁ g₂
inst✝² : HasPushout g₃ g₄
inst✝¹ : HasPushout (g₃ ≫ pushout.inr) g₄
inst✝ : HasPushout g₁ (g₂ ≫ pushout.inl)
⊢ pushout.inr ≫ pushout.inl ≫ (pushoutAssoc g₁ g₂ g₃ g₄).hom =
    pushout.inr ≫
      pushout.desc pushout.inl (pushout.inl ≫ pushout.inr) (_ : g₁ ≫ pushout.inl = g₂ ≫ pushout.inl ≫ pushout.inr)

Next tactic:
congr 1