l3lab/ntp-mathlib huggingface dataset:
/-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair where
  functor :=
    parallelFamily fun p => cond p.down WalkingParallelPairHom.left WalkingParallelPairHom.right
  inverse := parallelPair (line (ULift.up true)) (line (ULift.up false))
  unitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|⟨_|_⟩) <;> aesop_cat)
  counitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|_|_) <;> 

Proof state:
case id
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
X✝ : WalkingParallelPair
⊢ (parallelPair (line { down := true }) (line { down := false }) ⋙
            parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).map
        (WalkingParallelPairHom.id X✝) ≫
      ((fun X =>
            eqToIso
              (_ :
                (parallelPair (line { down := true }) (line { down := false }) ⋙
                        parallelFamily fun p =>
                          bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
                    X =
                  (𝟭 WalkingParallelPair).obj X))
          X✝).hom =
    ((fun X =>
            eqToIso
              (_ :
                (parallelPair (line { down := true }) (line { down := false }) ⋙
                        parallelFamily fun p =>
                          bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
                    X =
                  (𝟭 WalkingParallelPair).obj X))
          X✝).hom ≫
      (𝟭 WalkingParallelPair).map (WalkingParallelPairHom.id X✝)

Next tactic:
aesop_cat
/-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair where
  functor :=
    parallelFamily fun p => cond p.down WalkingParallelPairHom.left WalkingParallelPairHom.right
  inverse := parallelPair (line (ULift.up true)) (line (ULift.up false))
  unitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|⟨_|_⟩) <;> aesop_cat)
  counitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|_|_) <;> aesop_cat)
  functor_unitIso_comp := by 

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
⊢ ∀ (X : WalkingParallelFamily (ULift.{w, 0} Bool)),
    (parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).map
          ((NatIso.ofComponents fun X =>
                  eqToIso
                    (_ :
                      (𝟭 (WalkingParallelFamily (ULift.{w, 0} Bool))).obj X =
                        ((parallelFamily fun p =>
                                bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right) ⋙
                              parallelPair (line { down := true }) (line { down := false })).obj
                          X)).hom.app
            X) ≫
        (NatIso.ofComponents fun X =>
                eqToIso
                  (_ :
                    (parallelPair (line { down := true }) (line { down := false }) ⋙
                            parallelFamily fun p =>
                              bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
                        X =
                      (𝟭 WalkingParallelPair).obj X)).hom.app
          ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
            X) =
      𝟙 ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj X)

Next tactic:
rintro (_|_)
/-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair where
  functor :=
    parallelFamily fun p => cond p.down WalkingParallelPairHom.left WalkingParallelPairHom.right
  inverse := parallelPair (line (ULift.up true)) (line (ULift.up false))
  unitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|⟨_|_⟩) <;> aesop_cat)
  counitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|_|_) <;> aesop_cat)
  functor_unitIso_comp := by rintro (_|_) <;> 

Proof state:
case zero
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
⊢ (parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).map
        ((NatIso.ofComponents fun X =>
                eqToIso
                  (_ :
                    (𝟭 (WalkingParallelFamily (ULift.{w, 0} Bool))).obj X =
                      ((parallelFamily fun p =>
                              bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right) ⋙
                            parallelPair (line { down := true }) (line { down := false })).obj
                        X)).hom.app
          zero) ≫
      (NatIso.ofComponents fun X =>
              eqToIso
                (_ :
                  (parallelPair (line { down := true }) (line { down := false }) ⋙
                          parallelFamily fun p =>
                            bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
                      X =
                    (𝟭 WalkingParallelPair).obj X)).hom.app
        ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
          zero) =
    𝟙 ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj zero)

Next tactic:
aesop_cat
/-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair where
  functor :=
    parallelFamily fun p => cond p.down WalkingParallelPairHom.left WalkingParallelPairHom.right
  inverse := parallelPair (line (ULift.up true)) (line (ULift.up false))
  unitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|⟨_|_⟩) <;> aesop_cat)
  counitIso := NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl)) (by
    rintro _ _ (_|_|_) <;> aesop_cat)
  functor_unitIso_comp := by rintro (_|_) <;> 

Proof state:
case one
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
⊢ (parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).map
        ((NatIso.ofComponents fun X =>
                eqToIso
                  (_ :
                    (𝟭 (WalkingParallelFamily (ULift.{w, 0} Bool))).obj X =
                      ((parallelFamily fun p =>
                              bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right) ⋙
                            parallelPair (line { down := true }) (line { down := false })).obj
                        X)).hom.app
          one) ≫
      (NatIso.ofComponents fun X =>
              eqToIso
                (_ :
                  (parallelPair (line { down := true }) (line { down := false }) ⋙
                          parallelFamily fun p =>
                            bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
                      X =
                    (𝟭 WalkingParallelPair).obj X)).hom.app
        ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj
          one) =
    𝟙 ((parallelFamily fun p => bif p.down then WalkingParallelPairHom.left else WalkingParallelPairHom.right).obj one)

Next tactic:
aesop_cat
@[reassoc (attr := simp)]
theorem Trident.app_zero (s : Trident f) (j : J) : s.π.app zero ≫ f j = s.π.app one := by
  

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
s : Trident f
j : J
⊢ s.π.app zero ≫ f j = s.π.app one

Next tactic:
rw [← s.w (line j), parallelFamily_map_left]
@[reassoc (attr := simp)]
theorem Cotrident.app_one (s : Cotrident f) (j : J) : f j ≫ s.ι.app one = s.ι.app zero := by
  

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
s : Cotrident f
j : J
⊢ f j ≫ s.ι.app one = s.ι.app zero

Next tactic:
rw [← s.w (line j), parallelFamily_map_left]
/-- A trident on `f : J → (X ⟶ Y)` is determined by the morphism `ι : P ⟶ X` satisfying
`∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂`.
-/
@[simps]
def Trident.ofι [Nonempty J] {P : C} (ι : P ⟶ X) (w : ∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂) : Trident f
    where
  pt := P
  π :=
    { app := fun X => WalkingParallelFamily.casesOn X ι (ι ≫ f (Classical.arbitrary J))
      naturality := fun i j f => by
        

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f✝ : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
ι : P ⟶ X
w : ∀ (j₁ j₂ : J), ι ≫ f✝ j₁ = ι ≫ f✝ j₂
i j : WalkingParallelFamily J
f : i ⟶ j
⊢ ((Functor.const (WalkingParallelFamily J)).obj P).map f ≫
      (fun X_1 => WalkingParallelFamily.casesOn X_1 ι (ι ≫ f✝ (Classical.arbitrary J))) j =
    (fun X_1 => WalkingParallelFamily.casesOn X_1 ι (ι ≫ f✝ (Classical.arbitrary J))) i ≫ (parallelFamily f✝).map f

Next tactic:
dsimp
/-- A trident on `f : J → (X ⟶ Y)` is determined by the morphism `ι : P ⟶ X` satisfying
`∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂`.
-/
@[simps]
def Trident.ofι [Nonempty J] {P : C} (ι : P ⟶ X) (w : ∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂) : Trident f
    where
  pt := P
  π :=
    { app := fun X => WalkingParallelFamily.casesOn X ι (ι ≫ f (Classical.arbitrary J))
      naturality := fun i j f => by
        dsimp
        

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f✝ : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
ι : P ⟶ X
w : ∀ (j₁ j₂ : J), ι ≫ f✝ j₁ = ι ≫ f✝ j₂
i j : WalkingParallelFamily J
f : i ⟶ j
⊢ 𝟙 P ≫ WalkingParallelFamily.rec ι (ι ≫ f✝ (Classical.arbitrary J)) j =
    WalkingParallelFamily.rec ι (ι ≫ f✝ (Classical.arbitrary J)) i ≫ (parallelFamily f✝).map f

Next tactic:
cases' f with _ k
/-- A trident on `f : J → (X ⟶ Y)` is determined by the morphism `ι : P ⟶ X` satisfying
`∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂`.
-/
@[simps]
def Trident.ofι [Nonempty J] {P : C} (ι : P ⟶ X) (w : ∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂) : Trident f
    where
  pt := P
  π :=
    { app := fun X => WalkingParallelFamily.casesOn X ι (ι ≫ f (Classical.arbitrary J))
      naturality := fun i j f => by
        dsimp
        cases' f with _ k
        · 

Proof state:
case id
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
ι : P ⟶ X
w : ∀ (j₁ j₂ : J), ι ≫ f j₁ = ι ≫ f j₂
i : WalkingParallelFamily J
⊢ 𝟙 P ≫ WalkingParallelFamily.rec ι (ι ≫ f (Classical.arbitrary J)) i =
    WalkingParallelFamily.rec ι (ι ≫ f (Classical.arbitrary J)) i ≫ (parallelFamily f).map (Hom.id i)

Next tactic:
simp
/-- A trident on `f : J → (X ⟶ Y)` is determined by the morphism `ι : P ⟶ X` satisfying
`∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂`.
-/
@[simps]
def Trident.ofι [Nonempty J] {P : C} (ι : P ⟶ X) (w : ∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂) : Trident f
    where
  pt := P
  π :=
    { app := fun X => WalkingParallelFamily.casesOn X ι (ι ≫ f (Classical.arbitrary J))
      naturality := fun i j f => by
        dsimp
        cases' f with _ k
        · simp
        · 

Proof state:
case line
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
ι : P ⟶ X
w : ∀ (j₁ j₂ : J), ι ≫ f j₁ = ι ≫ f j₂
k : J
⊢ 𝟙 P ≫ WalkingParallelFamily.rec ι (ι ≫ f (Classical.arbitrary J)) one =
    WalkingParallelFamily.rec ι (ι ≫ f (Classical.arbitrary J)) zero ≫ (parallelFamily f).map (line k)

Next tactic:
simp [w (Classical.arbitrary J) k]
/-- A cotrident on `f : J → (X ⟶ Y)` is determined by the morphism `π : Y ⟶ P` satisfying
`∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π`.
-/
@[simps]
def Cotrident.ofπ [Nonempty J] {P : C} (π : Y ⟶ P) (w : ∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π) :
    Cotrident f where
  pt := P
  ι :=
    { app := fun X => WalkingParallelFamily.casesOn X (f (Classical.arbitrary J) ≫ π) π
      naturality := fun i j f => by
        

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f✝ : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
π : Y ⟶ P
w : ∀ (j₁ j₂ : J), f✝ j₁ ≫ π = f✝ j₂ ≫ π
i j : WalkingParallelFamily J
f : i ⟶ j
⊢ (parallelFamily f✝).map f ≫ (fun X_1 => WalkingParallelFamily.casesOn X_1 (f✝ (Classical.arbitrary J) ≫ π) π) j =
    (fun X_1 => WalkingParallelFamily.casesOn X_1 (f✝ (Classical.arbitrary J) ≫ π) π) i ≫
      ((Functor.const (WalkingParallelFamily J)).obj P).map f

Next tactic:
dsimp
/-- A cotrident on `f : J → (X ⟶ Y)` is determined by the morphism `π : Y ⟶ P` satisfying
`∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π`.
-/
@[simps]
def Cotrident.ofπ [Nonempty J] {P : C} (π : Y ⟶ P) (w : ∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π) :
    Cotrident f where
  pt := P
  ι :=
    { app := fun X => WalkingParallelFamily.casesOn X (f (Classical.arbitrary J) ≫ π) π
      naturality := fun i j f => by
        dsimp
        

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f✝ : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
π : Y ⟶ P
w : ∀ (j₁ j₂ : J), f✝ j₁ ≫ π = f✝ j₂ ≫ π
i j : WalkingParallelFamily J
f : i ⟶ j
⊢ (parallelFamily f✝).map f ≫ WalkingParallelFamily.rec (f✝ (Classical.arbitrary J) ≫ π) π j =
    WalkingParallelFamily.rec (f✝ (Classical.arbitrary J) ≫ π) π i ≫ 𝟙 P

Next tactic:
cases' f with _ k
/-- A cotrident on `f : J → (X ⟶ Y)` is determined by the morphism `π : Y ⟶ P` satisfying
`∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π`.
-/
@[simps]
def Cotrident.ofπ [Nonempty J] {P : C} (π : Y ⟶ P) (w : ∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π) :
    Cotrident f where
  pt := P
  ι :=
    { app := fun X => WalkingParallelFamily.casesOn X (f (Classical.arbitrary J) ≫ π) π
      naturality := fun i j f => by
        dsimp
        cases' f with _ k
        · 

Proof state:
case id
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
π : Y ⟶ P
w : ∀ (j₁ j₂ : J), f j₁ ≫ π = f j₂ ≫ π
i : WalkingParallelFamily J
⊢ (parallelFamily f).map (Hom.id i) ≫ WalkingParallelFamily.rec (f (Classical.arbitrary J) ≫ π) π i =
    WalkingParallelFamily.rec (f (Classical.arbitrary J) ≫ π) π i ≫ 𝟙 P

Next tactic:
simp
/-- A cotrident on `f : J → (X ⟶ Y)` is determined by the morphism `π : Y ⟶ P` satisfying
`∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π`.
-/
@[simps]
def Cotrident.ofπ [Nonempty J] {P : C} (π : Y ⟶ P) (w : ∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π) :
    Cotrident f where
  pt := P
  ι :=
    { app := fun X => WalkingParallelFamily.casesOn X (f (Classical.arbitrary J) ≫ π) π
      naturality := fun i j f => by
        dsimp
        cases' f with _ k
        · simp
        · 

Proof state:
case line
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
P : C
π : Y ⟶ P
w : ∀ (j₁ j₂ : J), f j₁ ≫ π = f j₂ ≫ π
k : J
⊢ (parallelFamily f).map (line k) ≫ WalkingParallelFamily.rec (f (Classical.arbitrary J) ≫ π) π one =
    WalkingParallelFamily.rec (f (Classical.arbitrary J) ≫ π) π zero ≫ 𝟙 P

Next tactic:
simp [w (Classical.arbitrary J) k]
@[reassoc]
theorem Trident.condition (j₁ j₂ : J) (t : Trident f) : t.ι ≫ f j₁ = t.ι ≫ f j₂ := by
  

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
j₁ j₂ : J
t : Trident f
⊢ ι t ≫ f j₁ = ι t ≫ f j₂

Next tactic:
rw [t.app_zero, t.app_zero]
@[reassoc]
theorem Cotrident.condition (j₁ j₂ : J) (t : Cotrident f) : f j₁ ≫ t.π = f j₂ ≫ t.π := by
  

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
j₁ j₂ : J
t : Cotrident f
⊢ f j₁ ≫ π t = f j₂ ≫ π t

Next tactic:
rw [t.app_one, t.app_one]
/-- To check whether two maps are equalized by both maps of a trident, it suffices to check it for
the first map -/
theorem Trident.equalizer_ext [Nonempty J] (s : Trident f) {W : C} {k l : W ⟶ s.pt}
    (h : k ≫ s.ι = l ≫ s.ι) : ∀ j : WalkingParallelFamily J, k ≫ s.π.app j = l ≫ s.π.app j
  | zero => h
  | one => by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
s : Trident f
W : C
k l : W ⟶ s.pt
h : k ≫ ι s = l ≫ ι s
⊢ k ≫ s.π.app one = l ≫ s.π.app one

Next tactic:
rw [← s.app_zero (Classical.arbitrary J), reassoc_of% h]
/-- To check whether two maps are coequalized by both maps of a cotrident, it suffices to check it
for the second map -/
theorem Cotrident.coequalizer_ext [Nonempty J] (s : Cotrident f) {W : C} {k l : s.pt ⟶ W}
    (h : s.π ≫ k = s.π ≫ l) : ∀ j : WalkingParallelFamily J, s.ι.app j ≫ k = s.ι.app j ≫ l
  | zero => by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
s : Cotrident f
W : C
k l : s.pt ⟶ W
h : π s ≫ k = π s ≫ l
⊢ s.ι.app zero ≫ k = s.ι.app zero ≫ l

Next tactic:
rw [← s.app_one (Classical.arbitrary J), Category.assoc, Category.assoc, h]
/-- This is a slightly more convenient method to verify that a trident is a limit cone. It
    only asks for a proof of facts that carry any mathematical content -/
def Trident.IsLimit.mk [Nonempty J] (t : Trident f) (lift : ∀ s : Trident f, s.pt ⟶ t.pt)
    (fac : ∀ s : Trident f, lift s ≫ t.ι = s.ι)
    (uniq :
      ∀ (s : Trident f) (m : s.pt ⟶ t.pt)
        (_ : ∀ j : WalkingParallelFamily J, m ≫ t.π.app j = s.π.app j), m = lift s) :
    IsLimit t :=
  { lift
    fac := fun s j =>
      WalkingParallelFamily.casesOn j (fac s)
        (by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
t : Trident f
lift : (s : Trident f) → s.pt ⟶ t.pt
fac : ∀ (s : Trident f), lift s ≫ ι t = ι s
uniq : ∀ (s : Trident f) (m : s.pt ⟶ t.pt), (∀ (j : WalkingParallelFamily J), m ≫ t.π.app j = s.π.app j) → m = lift s
s : Cone (parallelFamily f)
j : WalkingParallelFamily J
⊢ lift s ≫ t.π.app one = s.π.app one

Next tactic:
rw [← t.w (line (Classical.arbitrary J)), reassoc_of% fac, s.w]
/-- This is a slightly more convenient method to verify that a cotrident is a colimit cocone. It
    only asks for a proof of facts that carry any mathematical content -/
def Cotrident.IsColimit.mk [Nonempty J] (t : Cotrident f) (desc : ∀ s : Cotrident f, t.pt ⟶ s.pt)
    (fac : ∀ s : Cotrident f, t.π ≫ desc s = s.π)
    (uniq :
      ∀ (s : Cotrident f) (m : t.pt ⟶ s.pt)
        (_ : ∀ j : WalkingParallelFamily J, t.ι.app j ≫ m = s.ι.app j), m = desc s) :
    IsColimit t :=
  { desc
    fac := fun s j =>
      WalkingParallelFamily.casesOn j (by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
t : Cotrident f
desc : (s : Cotrident f) → t.pt ⟶ s.pt
fac : ∀ (s : Cotrident f), π t ≫ desc s = π s
uniq : ∀ (s : Cotrident f) (m : t.pt ⟶ s.pt), (∀ (j : WalkingParallelFamily J), t.ι.app j ≫ m = s.ι.app j) → m = desc s
s : Cocone (parallelFamily f)
j : WalkingParallelFamily J
⊢ t.ι.app zero ≫ desc s = s.ι.app zero

Next tactic:
rw [← t.w_assoc (line (Classical.arbitrary J)), fac, s.w]
/--
Given a limit cone for the family `f : J → (X ⟶ Y)`, for any `Z`, morphisms from `Z` to its point
are in bijection with morphisms `h : Z ⟶ X` such that `∀ j₁ j₂, h ≫ f j₁ = h ≫ f j₂`.
Further, this bijection is natural in `Z`: see `Trident.Limits.homIso_natural`.
-/
@[simps]
def Trident.IsLimit.homIso [Nonempty J] {t : Trident f} (ht : IsLimit t) (Z : C) :
    (Z ⟶ t.pt) ≃ { h : Z ⟶ X // ∀ j₁ j₂, h ≫ f j₁ = h ≫ f j₂ } where
  toFun k := ⟨k ≫ t.ι, by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
t : Trident f
ht : IsLimit t
Z : C
k : Z ⟶ t.pt
⊢ ∀ (j₁ j₂ : J), (k ≫ ι t) ≫ f j₁ = (k ≫ ι t) ≫ f j₂

Next tactic:
simp
/-- Given a colimit cocone for the family `f : J → (X ⟶ Y)`, for any `Z`, morphisms from the cocone
point to `Z` are in bijection with morphisms `h : Z ⟶ X` such that
`∀ j₁ j₂, f j₁ ≫ h = f j₂ ≫ h`.  Further, this bijection is natural in `Z`: see
`Cotrident.IsColimit.homIso_natural`.
-/
@[simps]
def Cotrident.IsColimit.homIso [Nonempty J] {t : Cotrident f} (ht : IsColimit t) (Z : C) :
    (t.pt ⟶ Z) ≃ { h : Y ⟶ Z // ∀ j₁ j₂, f j₁ ≫ h = f j₂ ≫ h } where
  toFun k := ⟨t.π ≫ k, by 

Proof state:
J : Type w
C : Type u
inst✝¹ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
inst✝ : Nonempty J
t : Cotrident f
ht : IsColimit t
Z : C
k : t.pt ⟶ Z
⊢ ∀ (j₁ j₂ : J), f j₁ ≫ π t ≫ k = f j₂ ≫ π t ≫ k

Next tactic:
simp
/-- This is a helper construction that can be useful when verifying that a category has certain wide
    equalizers. Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (λ j, F.map (line j))`, and a trident on `λ j, F.map (line j)`, we get a cone
    on `F`.

    If you're thinking about using this, have a look at
    `hasWideEqualizers_of_hasLimit_parallelFamily`, which you may find to be an easier way of
    achieving your goal. -/
def Cone.ofTrident {F : WalkingParallelFamily J ⥤ C} (t : Trident fun j => F.map (line j)) : Cone F
    where
  pt := t.pt
  π :=
    { app := fun X => t.π.app X ≫ eqToHom (by 

Proof state:
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X✝ Y : C
f : J → (X✝ ⟶ Y)
F : WalkingParallelFamily J ⥤ C
t : Trident fun j => F.map (line j)
X : WalkingParallelFamily J
⊢ (parallelFamily fun j => F.map (line j)).obj X = F.obj X

Next tactic:
cases X
/-- This is a helper construction that can be useful when verifying that a category has certain wide
    equalizers. Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (λ j, F.map (line j))`, and a trident on `λ j, F.map (line j)`, we get a cone
    on `F`.

    If you're thinking about using this, have a look at
    `hasWideEqualizers_of_hasLimit_parallelFamily`, which you may find to be an easier way of
    achieving your goal. -/
def Cone.ofTrident {F : WalkingParallelFamily J ⥤ C} (t : Trident fun j => F.map (line j)) : Cone F
    where
  pt := t.pt
  π :=
    { app := fun X => t.π.app X ≫ eqToHom (by cases X <;> 

Proof state:
case zero
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
F : WalkingParallelFamily J ⥤ C
t : Trident fun j => F.map (line j)
⊢ (parallelFamily fun j => F.map (line j)).obj zero = F.obj zero

Next tactic:
aesop_cat
/-- This is a helper construction that can be useful when verifying that a category has certain wide
    equalizers. Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (λ j, F.map (line j))`, and a trident on `λ j, F.map (line j)`, we get a cone
    on `F`.

    If you're thinking about using this, have a look at
    `hasWideEqualizers_of_hasLimit_parallelFamily`, which you may find to be an easier way of
    achieving your goal. -/
def Cone.ofTrident {F : WalkingParallelFamily J ⥤ C} (t : Trident fun j => F.map (line j)) : Cone F
    where
  pt := t.pt
  π :=
    { app := fun X => t.π.app X ≫ eqToHom (by cases X <;> 

Proof state:
case one
J : Type w
C : Type u
inst✝ : Category.{v, u} C
X Y : C
f : J → (X ⟶ Y)
F : WalkingParallelFamily J ⥤ C
t : Trident fun j => F.map (line j)
⊢ (parallelFamily fun j => F.map (line j)).obj one = F.obj one

Next tactic:
aesop_cat