l3lab/ntp-mathlib huggingface dataset:
/-- 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'
  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₁ ≫ 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:
have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
/-- 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'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ 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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
⊢ PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃

Next tactic:
rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
/-- 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'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
  

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₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ 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:
rcases PullbackCone.IsLimit.lift' H' s.fst (s.snd ≫ f₂) this with ⟨l₁, hl₁, 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
            rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc]))) :
    IsLimit (PullbackCone.mk _ _ h₁) := by
  fapply PullbackCone.isLimitAux'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
  rcases PullbackCone.IsLimit.lift' H' s.fst (s.snd ≫ f₂) 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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ { 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:
use l₁
/-- 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'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
  rcases PullbackCone.IsLimit.lift' H' s.fst (s.snd ≫ f₂) this 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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ 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:
use 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
            rw [← Category.assoc, h₁, Category.assoc, h₂, Category.assoc]))) :
    IsLimit (PullbackCone.mk _ _ h₁) := by
  fapply PullbackCone.isLimitAux'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
  rcases PullbackCone.IsLimit.lift' H' s.fst (s.snd ≫ f₂) this with ⟨l₁, hl₁, hl₁'⟩
  use l₁
  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 : IsLimit (PullbackCone.mk i₂ f₂ h₂)
H' : IsLimit (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ 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:
constructor
/-- 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'
  intro s
  have : s.fst ≫ g₁ ≫ g₂ = (s.snd ≫ f₂) ≫ i₃ := by
    rw [← Category.assoc, s.condition, Category.assoc, Category.assoc, h₂]
  rcases PullbackCone.IsLimit.lift' H' s.fst (s.snd ≫ f₂) this with ⟨l₁, hl₁, hl₁'⟩
  use l₁
  use hl₁
  constructor
  · 

Proof state:
case right.left
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₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁) = PullbackCone.snd s

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

Proof state:
case right.left.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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ (l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂) =
    PullbackCone.snd s ≫ PullbackCone.fst (PullbackCone.mk i₂ f₂ h₂)

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

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

Proof state:
case right.left.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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ (l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ f₁ h₁)) ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂) =
    PullbackCone.snd s ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂)

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

Proof state:
case right.left.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₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃))
s : PullbackCone g₁ i₂
this : PullbackCone.fst s ≫ g₁ ≫ g₂ = (PullbackCone.snd s ≫ f₂) ≫ i₃
l₁ : s.pt ⟶ (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)).pt
hl₁ : l₁ ≫ PullbackCone.fst (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.fst s
hl₁' :
  l₁ ≫ PullbackCone.snd (PullbackCone.mk i₁ (f₁ ≫ f₂) (_ : i₁ ≫ g₁ ≫ g₂ = (f₁ ≫ f₂) ≫ i₃)) = PullbackCone.snd s ≫ f₂
⊢ PullbackCone.snd s ≫ f₂ = PullbackCone.snd s ≫ PullbackCone.snd (PullbackCone.mk i₂ f₂ h₂)

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

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

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

Next tactic:
apply PullbackCone.IsLimit.hom_ext H'