l3lab/ntp-mathlib huggingface dataset:
/-- The pullback over the terminal object is the product -/
def isProductOfIsTerminalIsPullback {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z)
    (H₂ : IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _))) :
    IsLimit (BinaryFan.mk h k) := by
  apply isBinaryProductOfIsTerminalIsPullback _ _ H₁
  

Proof state:
case hc
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (PullbackCone.mk h k (_ : h ≫ f = k ≫ g))
⊢ IsLimit
    (PullbackCone.mk ((BinaryFan.mk h k).π.app { as := WalkingPair.left })
      ((BinaryFan.mk h k).π.app { as := WalkingPair.right })
      (_ :
        (BinaryFan.mk h k).π.app { as := WalkingPair.left } ≫ ?f =
          (BinaryFan.mk h k).π.app { as := WalkingPair.right } ≫ ?g))
case f
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (PullbackCone.mk h k (_ : h ≫ f = k ≫ g))
⊢ (pair X Y).obj { as := WalkingPair.left } ⟶ Z
case g
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (PullbackCone.mk h k (_ : h ≫ f = k ≫ g))
⊢ (pair X Y).obj { as := WalkingPair.right } ⟶ Z

Next tactic:
exact H₂
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  

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

Next tactic:
apply PullbackCone.isLimitAux'
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  

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

Next tactic:
intro s
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  

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

Next tactic:
use H₂.lift (BinaryFan.mk s.fst s.snd)
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  

Proof state:
case property
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
⊢ IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫
        PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) =
      PullbackCone.fst s ∧
    IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫
          PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) =
        PullbackCone.snd s ∧
      ∀ {m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt},
        m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s →
          m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s →
            m = IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s))

Next tactic:
use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  

Proof state:
case right
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
⊢ IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫
        PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) =
      PullbackCone.snd s ∧
    ∀ {m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt},
      m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s →
        m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s →
          m = IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s))

Next tactic:
use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
  

Proof state:
case right
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
⊢ ∀ {m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt},
    m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s →
      m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s →
        m = IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s))

Next tactic:
intro m h₁ h₂
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
  intro m h₁ h₂
  

Proof state:
case right
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt
h₁ : m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s
h₂ : m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s
⊢ m = IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s))

Next tactic:
apply H₂.hom_ext
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
  intro m h₁ h₂
  apply H₂.hom_ext
  

Proof state:
case right
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt
h₁ : m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s
h₂ : m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s
⊢ ∀ (j : Discrete WalkingPair),
    m ≫ (BinaryFan.mk h k).π.app j =
      IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫ (BinaryFan.mk h k).π.app j

Next tactic:
rintro ⟨⟨⟩⟩
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
  intro m h₁ h₂
  apply H₂.hom_ext
  rintro ⟨⟨⟩⟩
  · 

Proof state:
case right.mk.left
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt
h₁ : m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s
h₂ : m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s
⊢ m ≫ (BinaryFan.mk h k).π.app { as := WalkingPair.left } =
    IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫
      (BinaryFan.mk h k).π.app { as := WalkingPair.left }

Next tactic:
exact h₁.trans (H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩).symm
/-- The product is the pullback over the terminal object. -/
def isPullbackOfIsTerminalIsProduct {W X Y Z : C} (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ X) (k : W ⟶ Y)
    (H₁ : IsTerminal Z) (H₂ : IsLimit (BinaryFan.mk h k)) :
    IsLimit (PullbackCone.mk _ _ (show h ≫ f = k ≫ g from H₁.hom_ext _ _)) := by
  apply PullbackCone.isLimitAux'
  intro s
  use H₂.lift (BinaryFan.mk s.fst s.snd)
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩
  use H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩
  intro m h₁ h₂
  apply H₂.hom_ext
  rintro ⟨⟨⟩⟩
  · exact h₁.trans (H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.left⟩).symm
  · 

Proof state:
case right.mk.right
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F : C ⥤ D
W X Y Z : C
f : X ⟶ Z
g : Y ⟶ Z
h : W ⟶ X
k : W ⟶ Y
H₁ : IsTerminal Z
H₂ : IsLimit (BinaryFan.mk h k)
s : PullbackCone f g
m : s.pt ⟶ (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)).pt
h₁ : m ≫ PullbackCone.fst (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.fst s
h₂ : m ≫ PullbackCone.snd (PullbackCone.mk h k (_ : h ≫ f = k ≫ g)) = PullbackCone.snd s
⊢ m ≫ (BinaryFan.mk h k).π.app { as := WalkingPair.right } =
    IsLimit.lift H₂ (BinaryFan.mk (PullbackCone.fst s) (PullbackCone.snd s)) ≫
      (BinaryFan.mk h k).π.app { as := WalkingPair.right }

Next tactic:
exact h₂.trans (H₂.fac (BinaryFan.mk s.fst s.snd) ⟨WalkingPair.right⟩).symm
/-- A functor that preserves terminal objects and pullbacks preserves binary products. -/
noncomputable def preservesBinaryProductsOfPreservesTerminalAndPullbacks [HasTerminal C]
    [HasPullbacks C] [PreservesLimitsOfShape (Discrete.{0} PEmpty) F]
    [PreservesLimitsOfShape WalkingCospan F] : PreservesLimitsOfShape (Discrete WalkingPair) F :=
  ⟨fun {K} =>
    preservesLimitOfPreservesLimitCone (limitConeOfTerminalAndPullbacks K).2
      (by
        

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u'
inst✝⁴ : Category.{v', u'} D
F : C ⥤ D
inst✝³ : HasTerminal C
inst✝² : HasPullbacks C
inst✝¹ : PreservesLimitsOfShape (Discrete PEmpty.{1}) F
inst✝ : PreservesLimitsOfShape WalkingCospan F
K : Discrete WalkingPair ⥤ C
⊢ IsLimit (F.mapCone (limitConeOfTerminalAndPullbacks K).cone)

Next tactic:
apply
          isBinaryProductOfIsTerminalIsPullback _ _ (isLimitOfHasTerminalOfPreservesLimit F)
/-- A functor that preserves terminal objects and pullbacks preserves binary products. -/
noncomputable def preservesBinaryProductsOfPreservesTerminalAndPullbacks [HasTerminal C]
    [HasPullbacks C] [PreservesLimitsOfShape (Discrete.{0} PEmpty) F]
    [PreservesLimitsOfShape WalkingCospan F] : PreservesLimitsOfShape (Discrete WalkingPair) F :=
  ⟨fun {K} =>
    preservesLimitOfPreservesLimitCone (limitConeOfTerminalAndPullbacks K).2
      (by
        apply
          isBinaryProductOfIsTerminalIsPullback _ _ (isLimitOfHasTerminalOfPreservesLimit F)
        

Proof state:
case hc
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u'
inst✝⁴ : Category.{v', u'} D
F : C ⥤ D
inst✝³ : HasTerminal C
inst✝² : HasPullbacks C
inst✝¹ : PreservesLimitsOfShape (Discrete PEmpty.{1}) F
inst✝ : PreservesLimitsOfShape WalkingCospan F
K : Discrete WalkingPair ⥤ C
⊢ IsLimit
    (PullbackCone.mk ((F.mapCone (limitConeOfTerminalAndPullbacks K).cone).π.app { as := WalkingPair.left })
      ((F.mapCone (limitConeOfTerminalAndPullbacks K).cone).π.app { as := WalkingPair.right })
      (_ :
        (F.mapCone (limitConeOfTerminalAndPullbacks K).cone).π.app { as := WalkingPair.left } ≫ ?f =
          (F.mapCone (limitConeOfTerminalAndPullbacks K).cone).π.app { as := WalkingPair.right } ≫ ?g))
case f
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u'
inst✝⁴ : Category.{v', u'} D
F : C ⥤ D
inst✝³ : HasTerminal C
inst✝² : HasPullbacks C
inst✝¹ : PreservesLimitsOfShape (Discrete PEmpty.{1}) F
inst✝ : PreservesLimitsOfShape WalkingCospan F
K : Discrete WalkingPair ⥤ C
⊢ (K ⋙ F).obj { as := WalkingPair.left } ⟶ F.obj (⊤_ C)
case g
C : Type u
inst✝⁵ : Category.{v, u} C
D : Type u'
inst✝⁴ : Category.{v', u'} D
F : C ⥤ D
inst✝³ : HasTerminal C
inst✝² : HasPullbacks C
inst✝¹ : PreservesLimitsOfShape (Discrete PEmpty.{1}) F
inst✝ : PreservesLimitsOfShape WalkingCospan F
K : Discrete WalkingPair ⥤ C
⊢ (K ⋙ F).obj { as := WalkingPair.right } ⟶ F.obj (⊤_ C)

Next tactic:
apply isLimitOfHasPullbackOfPreservesLimit
/-- If a cospan is the pushout cospan under the initial object, then it is a binary coproduct. -/
def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : Cocone F) {X : C}
    (hX : IsInitial X) (f : X ⟶ F.obj ⟨WalkingPair.left⟩) (g : X ⟶ F.obj ⟨WalkingPair.right⟩)
    (hc :
      IsColimit
        (PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩) (c.ι.app ⟨WalkingPair.right⟩ : _) <|
          hX.hom_ext (f ≫ _) (g ≫ _))) :
    IsColimit c
    where
  desc s :=
    hc.desc
      (PushoutCocone.mk (s.ι.app ⟨WalkingPair.left⟩) (s.ι.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _))
  fac s j :=
    Discrete.casesOn j fun j =>
      WalkingPair.casesOn j (hc.fac _ WalkingSpan.left) (hc.fac _ WalkingSpan.right)
  uniq s m J := by
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ : C ⥤ D
F : Discrete WalkingPair ⥤ C
c : Cocone F
X : C
hX : IsInitial X
f : X ⟶ F.obj { as := WalkingPair.left }
g : X ⟶ F.obj { as := WalkingPair.right }
hc :
  IsColimit
    (PushoutCocone.mk (c.ι.app { as := WalkingPair.left }) (c.ι.app { as := WalkingPair.right })
      (_ : f ≫ c.ι.app { as := WalkingPair.left } = g ≫ c.ι.app { as := WalkingPair.right }))
s : Cocone F
m : c.pt ⟶ s.pt
J : ∀ (j : Discrete WalkingPair), c.ι.app j ≫ m = s.ι.app j
⊢ m =
    (fun s =>
        IsColimit.desc hc
          (PushoutCocone.mk (s.ι.app { as := WalkingPair.left }) (s.ι.app { as := WalkingPair.right })
            (_ : f ≫ s.ι.app { as := WalkingPair.left } = g ≫ s.ι.app { as := WalkingPair.right })))
      s

Next tactic:
let c' :=
      PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩ ≫ m) (c.ι.app ⟨WalkingPair.right⟩ ≫ m)
        (hX.hom_ext (f ≫ _) (g ≫ _))
/-- If a cospan is the pushout cospan under the initial object, then it is a binary coproduct. -/
def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : Cocone F) {X : C}
    (hX : IsInitial X) (f : X ⟶ F.obj ⟨WalkingPair.left⟩) (g : X ⟶ F.obj ⟨WalkingPair.right⟩)
    (hc :
      IsColimit
        (PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩) (c.ι.app ⟨WalkingPair.right⟩ : _) <|
          hX.hom_ext (f ≫ _) (g ≫ _))) :
    IsColimit c
    where
  desc s :=
    hc.desc
      (PushoutCocone.mk (s.ι.app ⟨WalkingPair.left⟩) (s.ι.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _))
  fac s j :=
    Discrete.casesOn j fun j =>
      WalkingPair.casesOn j (hc.fac _ WalkingSpan.left) (hc.fac _ WalkingSpan.right)
  uniq s m J := by
    let c' :=
      PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩ ≫ m) (c.ι.app ⟨WalkingPair.right⟩ ≫ m)
        (hX.hom_ext (f ≫ _) (g ≫ _))
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ : C ⥤ D
F : Discrete WalkingPair ⥤ C
c : Cocone F
X : C
hX : IsInitial X
f : X ⟶ F.obj { as := WalkingPair.left }
g : X ⟶ F.obj { as := WalkingPair.right }
hc :
  IsColimit
    (PushoutCocone.mk (c.ι.app { as := WalkingPair.left }) (c.ι.app { as := WalkingPair.right })
      (_ : f ≫ c.ι.app { as := WalkingPair.left } = g ≫ c.ι.app { as := WalkingPair.right }))
s : Cocone F
m : c.pt ⟶ s.pt
J : ∀ (j : Discrete WalkingPair), c.ι.app j ≫ m = s.ι.app j
c' : PushoutCocone f g :=
  PushoutCocone.mk (c.ι.app { as := WalkingPair.left } ≫ m) (c.ι.app { as := WalkingPair.right } ≫ m)
    (_ : f ≫ c.ι.app { as := WalkingPair.left } ≫ m = g ≫ c.ι.app { as := WalkingPair.right } ≫ m)
⊢ m =
    (fun s =>
        IsColimit.desc hc
          (PushoutCocone.mk (s.ι.app { as := WalkingPair.left }) (s.ι.app { as := WalkingPair.right })
            (_ : f ≫ s.ι.app { as := WalkingPair.left } = g ≫ s.ι.app { as := WalkingPair.right })))
      s

Next tactic:
dsimp
/-- If a cospan is the pushout cospan under the initial object, then it is a binary coproduct. -/
def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : Cocone F) {X : C}
    (hX : IsInitial X) (f : X ⟶ F.obj ⟨WalkingPair.left⟩) (g : X ⟶ F.obj ⟨WalkingPair.right⟩)
    (hc :
      IsColimit
        (PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩) (c.ι.app ⟨WalkingPair.right⟩ : _) <|
          hX.hom_ext (f ≫ _) (g ≫ _))) :
    IsColimit c
    where
  desc s :=
    hc.desc
      (PushoutCocone.mk (s.ι.app ⟨WalkingPair.left⟩) (s.ι.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _))
  fac s j :=
    Discrete.casesOn j fun j =>
      WalkingPair.casesOn j (hc.fac _ WalkingSpan.left) (hc.fac _ WalkingSpan.right)
  uniq s m J := by
    let c' :=
      PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩ ≫ m) (c.ι.app ⟨WalkingPair.right⟩ ≫ m)
        (hX.hom_ext (f ≫ _) (g ≫ _))
    dsimp; 

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ : C ⥤ D
F : Discrete WalkingPair ⥤ C
c : Cocone F
X : C
hX : IsInitial X
f : X ⟶ F.obj { as := WalkingPair.left }
g : X ⟶ F.obj { as := WalkingPair.right }
hc :
  IsColimit
    (PushoutCocone.mk (c.ι.app { as := WalkingPair.left }) (c.ι.app { as := WalkingPair.right })
      (_ : f ≫ c.ι.app { as := WalkingPair.left } = g ≫ c.ι.app { as := WalkingPair.right }))
s : Cocone F
m : c.pt ⟶ s.pt
J : ∀ (j : Discrete WalkingPair), c.ι.app j ≫ m = s.ι.app j
c' : PushoutCocone f g :=
  PushoutCocone.mk (c.ι.app { as := WalkingPair.left } ≫ m) (c.ι.app { as := WalkingPair.right } ≫ m)
    (_ : f ≫ c.ι.app { as := WalkingPair.left } ≫ m = g ≫ c.ι.app { as := WalkingPair.right } ≫ m)
⊢ m =
    IsColimit.desc hc
      (PushoutCocone.mk (s.ι.app { as := WalkingPair.left }) (s.ι.app { as := WalkingPair.right })
        (_ : f ≫ s.ι.app { as := WalkingPair.left } = g ≫ s.ι.app { as := WalkingPair.right }))

Next tactic:
rw [← J, ← J]
/-- If a cospan is the pushout cospan under the initial object, then it is a binary coproduct. -/
def isBinaryCoproductOfIsInitialIsPushout (F : Discrete WalkingPair ⥤ C) (c : Cocone F) {X : C}
    (hX : IsInitial X) (f : X ⟶ F.obj ⟨WalkingPair.left⟩) (g : X ⟶ F.obj ⟨WalkingPair.right⟩)
    (hc :
      IsColimit
        (PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩) (c.ι.app ⟨WalkingPair.right⟩ : _) <|
          hX.hom_ext (f ≫ _) (g ≫ _))) :
    IsColimit c
    where
  desc s :=
    hc.desc
      (PushoutCocone.mk (s.ι.app ⟨WalkingPair.left⟩) (s.ι.app ⟨WalkingPair.right⟩) (hX.hom_ext _ _))
  fac s j :=
    Discrete.casesOn j fun j =>
      WalkingPair.casesOn j (hc.fac _ WalkingSpan.left) (hc.fac _ WalkingSpan.right)
  uniq s m J := by
    let c' :=
      PushoutCocone.mk (c.ι.app ⟨WalkingPair.left⟩ ≫ m) (c.ι.app ⟨WalkingPair.right⟩ ≫ m)
        (hX.hom_ext (f ≫ _) (g ≫ _))
    dsimp; rw [← J, ← J]
    

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
D : Type u'
inst✝ : Category.{v', u'} D
F✝ : C ⥤ D
F : Discrete WalkingPair ⥤ C
c : Cocone F
X : C
hX : IsInitial X
f : X ⟶ F.obj { as := WalkingPair.left }
g : X ⟶ F.obj { as := WalkingPair.right }
hc :
  IsColimit
    (PushoutCocone.mk (c.ι.app { as := WalkingPair.left }) (c.ι.app { as := WalkingPair.right })
      (_ : f ≫ c.ι.app { as := WalkingPair.left } = g ≫ c.ι.app { as := WalkingPair.right }))
s : Cocone F
m : c.pt ⟶ s.pt
J : ∀ (j : Discrete WalkingPair), c.ι.app j ≫ m = s.ι.app j
c' : PushoutCocone f g :=
  PushoutCocone.mk (c.ι.app { as := WalkingPair.left } ≫ m) (c.ι.app { as := WalkingPair.right } ≫ m)
    (_ : f ≫ c.ι.app { as := WalkingPair.left } ≫ m = g ≫ c.ι.app { as := WalkingPair.right } ≫ m)
⊢ m =
    IsColimit.desc hc
      (PushoutCocone.mk (c.ι.app { as := WalkingPair.left } ≫ m) (c.ι.app { as := WalkingPair.right } ≫ m)
        (_ : f ≫ c.ι.app { as := WalkingPair.left } ≫ m = g ≫ c.ι.app { as := WalkingPair.right } ≫ m))

Next tactic:
apply hc.hom_ext