l3lab/ntp-mathlib huggingface dataset:
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> 

Proof state:
case mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cone (pair X Y)
⊢ (fun s => BinaryFan.fst s ≫ b.inl + BinaryFan.snd s ≫ b.inr) s ≫
      (BinaryBicone.toCone b).π.app { as := WalkingPair.right } =
    s.π.app { as := WalkingPair.right }

Next tactic:
simp
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cone (pair X Y)
m : s.pt ⟶ (BinaryBicone.toCone b).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (BinaryBicone.toCone b).π.app j = s.π.app j
⊢ m = (fun s => BinaryFan.fst s ≫ b.inl + BinaryFan.snd s ≫ b.inr) s

Next tactic:
have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cone (pair X Y)
m : s.pt ⟶ (BinaryBicone.toCone b).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (BinaryBicone.toCone b).π.app j = s.π.app j
j : WalkingPair
W : C
h' : (pair X Y).obj { as := j } ⟶ W
⊢ m ≫ (BinaryBicone.toCone b).π.app { as := j } ≫ h' = s.π.app { as := j } ≫ h'

Next tactic:
rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cone (pair X Y)
m : s.pt ⟶ (BinaryBicone.toCone b).pt
h : ∀ (j : Discrete WalkingPair), m ≫ (BinaryBicone.toCone b).π.app j = s.π.app j
reassoced :
  ∀ (j : WalkingPair) {W : C} (h' : (pair X Y).obj { as := j } ⟶ W),
    m ≫ (BinaryBicone.toCone b).π.app { as := j } ≫ h' = s.π.app { as := j } ≫ h'
⊢ m = (fun s => BinaryFan.fst s ≫ b.inl + BinaryFan.snd s ≫ b.inr) s

Next tactic:
erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> simp }
  isColimit :=
    { desc := fun s =>
        (b.fst ≫ BinaryCofan.inl s : b.pt ⟶ s.pt) + (b.snd ≫ BinaryCofan.inr s : b.pt ⟶ s.pt)
      uniq := fun s m h => by
        erw [← Category.id_comp m, ← total, add_comp, Category.assoc, Category.assoc,
          h ⟨WalkingPair.left⟩, h ⟨WalkingPair.right⟩]
      fac := fun s j => by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cocone (pair X Y)
j : Discrete WalkingPair
⊢ (BinaryBicone.toCocone b).ι.app j ≫ (fun s => b.fst ≫ BinaryCofan.inl s + b.snd ≫ BinaryCofan.inr s) s = s.ι.app j

Next tactic:
rcases j with ⟨⟨⟩⟩
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> simp }
  isColimit :=
    { desc := fun s =>
        (b.fst ≫ BinaryCofan.inl s : b.pt ⟶ s.pt) + (b.snd ≫ BinaryCofan.inr s : b.pt ⟶ s.pt)
      uniq := fun s m h => by
        erw [← Category.id_comp m, ← total, add_comp, Category.assoc, Category.assoc,
          h ⟨WalkingPair.left⟩, h ⟨WalkingPair.right⟩]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> 

Proof state:
case mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cocone (pair X Y)
⊢ (BinaryBicone.toCocone b).ι.app { as := WalkingPair.left } ≫
      (fun s => b.fst ≫ BinaryCofan.inl s + b.snd ≫ BinaryCofan.inr s) s =
    s.ι.app { as := WalkingPair.left }

Next tactic:
simp
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> simp }
  isColimit :=
    { desc := fun s =>
        (b.fst ≫ BinaryCofan.inl s : b.pt ⟶ s.pt) + (b.snd ≫ BinaryCofan.inr s : b.pt ⟶ s.pt)
      uniq := fun s m h => by
        erw [← Category.id_comp m, ← total, add_comp, Category.assoc, Category.assoc,
          h ⟨WalkingPair.left⟩, h ⟨WalkingPair.right⟩]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> 

Proof state:
case mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cocone (pair X Y)
⊢ (BinaryBicone.toCocone b).ι.app { as := WalkingPair.right } ≫
      (fun s => b.fst ≫ BinaryCofan.inl s + b.snd ≫ BinaryCofan.inr s) s =
    s.ι.app { as := WalkingPair.right }

Next tactic:
simp
/-- In a preadditive category, we can construct a binary biproduct for `X Y : C` from
any binary bicone `b` satisfying `total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBinaryBilimitOfTotal {X Y : C} (b : BinaryBicone X Y)
    (total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt) : b.IsBilimit where
  isLimit :=
    { lift := fun s =>
      (BinaryFan.fst s ≫ b.inl : s.pt ⟶ b.pt) + (BinaryFan.snd s ≫ b.inr : s.pt ⟶ b.pt)
      uniq := fun s m h => by
        have reassoced (j : WalkingPair) {W : C} (h' : _ ⟶ W) :
          m ≫ b.toCone.π.app ⟨j⟩ ≫ h' = s.π.app ⟨j⟩ ≫ h' := by
            rw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        erw [← Category.comp_id m, ← total, comp_add, reassoced WalkingPair.left,
          reassoced WalkingPair.right]
      fac := fun s j => by rcases j with ⟨⟨⟩⟩ <;> simp }
  isColimit :=
    { desc := fun s =>
        (b.fst ≫ BinaryCofan.inl s : b.pt ⟶ s.pt) + (b.snd ≫ BinaryCofan.inr s : b.pt ⟶ s.pt)
      uniq := fun s m h => by
        

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
total : b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt
s : Cocone (pair X Y)
m : (BinaryBicone.toCocone b).pt ⟶ s.pt
h : ∀ (j : Discrete WalkingPair), (BinaryBicone.toCocone b).ι.app j ≫ m = s.ι.app j
⊢ m = (fun s => b.fst ≫ BinaryCofan.inl s + b.snd ≫ BinaryCofan.inr s) s

Next tactic:
erw [← Category.id_comp m, ← total, add_comp, Category.assoc, Category.assoc,
          h ⟨WalkingPair.left⟩, h ⟨WalkingPair.right⟩]
theorem IsBilimit.binary_total {X Y : C} {b : BinaryBicone X Y} (i : b.IsBilimit) :
    b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt :=
  i.isLimit.hom_ext fun j => by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
i : BinaryBicone.IsBilimit b
j : Discrete WalkingPair
⊢ (b.fst ≫ b.inl + b.snd ≫ b.inr) ≫ (BinaryBicone.toCone b).π.app j = 𝟙 b.pt ≫ (BinaryBicone.toCone b).π.app j

Next tactic:
rcases j with ⟨⟨⟩⟩
theorem IsBilimit.binary_total {X Y : C} {b : BinaryBicone X Y} (i : b.IsBilimit) :
    b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt :=
  i.isLimit.hom_ext fun j => by rcases j with ⟨⟨⟩⟩ <;> 

Proof state:
case mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
i : BinaryBicone.IsBilimit b
⊢ (b.fst ≫ b.inl + b.snd ≫ b.inr) ≫ (BinaryBicone.toCone b).π.app { as := WalkingPair.left } =
    𝟙 b.pt ≫ (BinaryBicone.toCone b).π.app { as := WalkingPair.left }

Next tactic:
simp
theorem IsBilimit.binary_total {X Y : C} {b : BinaryBicone X Y} (i : b.IsBilimit) :
    b.fst ≫ b.inl + b.snd ≫ b.inr = 𝟙 b.pt :=
  i.isLimit.hom_ext fun j => by rcases j with ⟨⟨⟩⟩ <;> 

Proof state:
case mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
b : BinaryBicone X Y
i : BinaryBicone.IsBilimit b
⊢ (b.fst ≫ b.inl + b.snd ≫ b.inr) ≫ (BinaryBicone.toCone b).π.app { as := WalkingPair.right } =
    𝟙 b.pt ≫ (BinaryBicone.toCone b).π.app { as := WalkingPair.right }

Next tactic:
simp
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inl = IsLimit.lift ht (BinaryFan.mk (𝟙 X) 0)

Next tactic:
apply ht.uniq (BinaryFan.mk (𝟙 X) 0)
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryFan.mk (𝟙 X) 0); 

Proof state:
case x
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ ∀ (j : Discrete WalkingPair), t.inl ≫ (BinaryBicone.toCone t).π.app j = (BinaryFan.mk (𝟙 X) 0).π.app j

Next tactic:
rintro ⟨⟨⟩⟩
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryFan.mk (𝟙 X) 0); rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inl ≫ (BinaryBicone.toCone t).π.app { as := WalkingPair.left } =
    (BinaryFan.mk (𝟙 X) 0).π.app { as := WalkingPair.left }

Next tactic:
dsimp
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryFan.mk (𝟙 X) 0); rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inl ≫ (BinaryBicone.toCone t).π.app { as := WalkingPair.right } =
    (BinaryFan.mk (𝟙 X) 0).π.app { as := WalkingPair.right }

Next tactic:
dsimp
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryFan.mk (𝟙 X) 0); rintro ⟨⟨⟩⟩ <;> dsimp <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inl ≫ t.fst = 𝟙 X

Next tactic:
simp
theorem inl_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inl = ht.lift (BinaryFan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryFan.mk (𝟙 X) 0); rintro ⟨⟨⟩⟩ <;> dsimp <;> 

Proof state:
case x.mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inl ≫ t.snd = 0

Next tactic:
simp
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inr = IsLimit.lift ht (BinaryFan.mk 0 (𝟙 Y))

Next tactic:
apply ht.uniq (BinaryFan.mk 0 (𝟙 Y))
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  apply ht.uniq (BinaryFan.mk 0 (𝟙 Y)); 

Proof state:
case x
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ ∀ (j : Discrete WalkingPair), t.inr ≫ (BinaryBicone.toCone t).π.app j = (BinaryFan.mk 0 (𝟙 Y)).π.app j

Next tactic:
rintro ⟨⟨⟩⟩
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  apply ht.uniq (BinaryFan.mk 0 (𝟙 Y)); rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inr ≫ (BinaryBicone.toCone t).π.app { as := WalkingPair.left } =
    (BinaryFan.mk 0 (𝟙 Y)).π.app { as := WalkingPair.left }

Next tactic:
dsimp
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  apply ht.uniq (BinaryFan.mk 0 (𝟙 Y)); rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inr ≫ (BinaryBicone.toCone t).π.app { as := WalkingPair.right } =
    (BinaryFan.mk 0 (𝟙 Y)).π.app { as := WalkingPair.right }

Next tactic:
dsimp
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  apply ht.uniq (BinaryFan.mk 0 (𝟙 Y)); rintro ⟨⟨⟩⟩ <;> dsimp <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inr ≫ t.fst = 0

Next tactic:
simp
theorem inr_of_isLimit {X Y : C} {t : BinaryBicone X Y} (ht : IsLimit t.toCone) :
    t.inr = ht.lift (BinaryFan.mk 0 (𝟙 Y)) := by
  apply ht.uniq (BinaryFan.mk 0 (𝟙 Y)); rintro ⟨⟨⟩⟩ <;> dsimp <;> 

Proof state:
case x.mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.inr ≫ t.snd = 𝟙 Y

Next tactic:
simp
/-- In a preadditive category, any binary bicone which is a limit cone is in fact a bilimit
    bicone. -/
def isBinaryBilimitOfIsLimit {X Y : C} (t : BinaryBicone X Y) (ht : IsLimit t.toCone) :
    t.IsBilimit :=
  isBinaryBilimitOfTotal _ (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ t.fst ≫ t.inl + t.snd ≫ t.inr = 𝟙 t.pt

Next tactic:
refine' BinaryFan.IsLimit.hom_ext ht _ _
/-- In a preadditive category, any binary bicone which is a limit cone is in fact a bilimit
    bicone. -/
def isBinaryBilimitOfIsLimit {X Y : C} (t : BinaryBicone X Y) (ht : IsLimit t.toCone) :
    t.IsBilimit :=
  isBinaryBilimitOfTotal _ (by refine' BinaryFan.IsLimit.hom_ext ht _ _ <;> 

Proof state:
case refine'_1
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ (t.fst ≫ t.inl + t.snd ≫ t.inr) ≫ BinaryFan.fst (BinaryBicone.toCone t) =
    𝟙 t.pt ≫ BinaryFan.fst (BinaryBicone.toCone t)

Next tactic:
simp
/-- In a preadditive category, any binary bicone which is a limit cone is in fact a bilimit
    bicone. -/
def isBinaryBilimitOfIsLimit {X Y : C} (t : BinaryBicone X Y) (ht : IsLimit t.toCone) :
    t.IsBilimit :=
  isBinaryBilimitOfTotal _ (by refine' BinaryFan.IsLimit.hom_ext ht _ _ <;> 

Proof state:
case refine'_2
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsLimit (BinaryBicone.toCone t)
⊢ (t.fst ≫ t.inl + t.snd ≫ t.inr) ≫ BinaryFan.snd (BinaryBicone.toCone t) =
    𝟙 t.pt ≫ BinaryFan.snd (BinaryBicone.toCone t)

Next tactic:
simp
/-- We can turn any limit cone over a pair into a bilimit bicone. -/
def binaryBiconeIsBilimitOfLimitConeOfIsLimit {X Y : C} {t : Cone (pair X Y)} (ht : IsLimit t) :
    (BinaryBicone.ofLimitCone ht).IsBilimit :=
  isBinaryBilimitOfTotal _ <| BinaryFan.IsLimit.hom_ext ht (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : Cone (pair X Y)
ht : IsLimit t
⊢ ((BinaryBicone.ofLimitCone ht).fst ≫ (BinaryBicone.ofLimitCone ht).inl +
        (BinaryBicone.ofLimitCone ht).snd ≫ (BinaryBicone.ofLimitCone ht).inr) ≫
      BinaryFan.fst t =
    𝟙 (BinaryBicone.ofLimitCone ht).pt ≫ BinaryFan.fst t

Next tactic:
simp
/-- We can turn any limit cone over a pair into a bilimit bicone. -/
def binaryBiconeIsBilimitOfLimitConeOfIsLimit {X Y : C} {t : Cone (pair X Y)} (ht : IsLimit t) :
    (BinaryBicone.ofLimitCone ht).IsBilimit :=
  isBinaryBilimitOfTotal _ <| BinaryFan.IsLimit.hom_ext ht (by simp) (by 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : Cone (pair X Y)
ht : IsLimit t
⊢ ((BinaryBicone.ofLimitCone ht).fst ≫ (BinaryBicone.ofLimitCone ht).inl +
        (BinaryBicone.ofLimitCone ht).snd ≫ (BinaryBicone.ofLimitCone ht).inr) ≫
      BinaryFan.snd t =
    𝟙 (BinaryBicone.ofLimitCone ht).pt ≫ BinaryFan.snd t

Next tactic:
simp
theorem fst_of_isColimit {X Y : C} {t : BinaryBicone X Y} (ht : IsColimit t.toCocone) :
    t.fst = ht.desc (BinaryCofan.mk (𝟙 X) 0) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsColimit (BinaryBicone.toCocone t)
⊢ t.fst = IsColimit.desc ht (BinaryCofan.mk (𝟙 X) 0)

Next tactic:
apply ht.uniq (BinaryCofan.mk (𝟙 X) 0)
theorem fst_of_isColimit {X Y : C} {t : BinaryBicone X Y} (ht : IsColimit t.toCocone) :
    t.fst = ht.desc (BinaryCofan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryCofan.mk (𝟙 X) 0)
  

Proof state:
case x
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsColimit (BinaryBicone.toCocone t)
⊢ ∀ (j : Discrete WalkingPair), (BinaryBicone.toCocone t).ι.app j ≫ t.fst = (BinaryCofan.mk (𝟙 X) 0).ι.app j

Next tactic:
rintro ⟨⟨⟩⟩
theorem fst_of_isColimit {X Y : C} {t : BinaryBicone X Y} (ht : IsColimit t.toCocone) :
    t.fst = ht.desc (BinaryCofan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryCofan.mk (𝟙 X) 0)
  rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsColimit (BinaryBicone.toCocone t)
⊢ (BinaryBicone.toCocone t).ι.app { as := WalkingPair.left } ≫ t.fst =
    (BinaryCofan.mk (𝟙 X) 0).ι.app { as := WalkingPair.left }

Next tactic:
dsimp
theorem fst_of_isColimit {X Y : C} {t : BinaryBicone X Y} (ht : IsColimit t.toCocone) :
    t.fst = ht.desc (BinaryCofan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryCofan.mk (𝟙 X) 0)
  rintro ⟨⟨⟩⟩ <;> 

Proof state:
case x.mk.right
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsColimit (BinaryBicone.toCocone t)
⊢ (BinaryBicone.toCocone t).ι.app { as := WalkingPair.right } ≫ t.fst =
    (BinaryCofan.mk (𝟙 X) 0).ι.app { as := WalkingPair.right }

Next tactic:
dsimp
theorem fst_of_isColimit {X Y : C} {t : BinaryBicone X Y} (ht : IsColimit t.toCocone) :
    t.fst = ht.desc (BinaryCofan.mk (𝟙 X) 0) := by
  apply ht.uniq (BinaryCofan.mk (𝟙 X) 0)
  rintro ⟨⟨⟩⟩ <;> dsimp <;> 

Proof state:
case x.mk.left
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
X Y : C
t : BinaryBicone X Y
ht : IsColimit (BinaryBicone.toCocone t)
⊢ t.inl ≫ t.fst = 𝟙 X

Next tactic:
simp