File: Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean

full_name: CategoryTheory.Limits.WalkingParallelFamily.one
code: /-- The type of objects for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily (J : Type w) : Type w
  | zero : WalkingParallelFamily J
  | one : WalkingParallelFamily J
goal: CategoryTheory.Limits.WalkingParallelFamily J

full_name: CategoryTheory.Limits.WalkingParallelFamily
code: /-- The type of objects for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily (J : Type w) : Type w
  | zero : WalkingParallelFamily J
  | one : WalkingParallelFamily J
goal: Type w

full_name: CategoryTheory.Limits.WalkingParallelFamily.zero
code: /-- The type of objects for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily (J : Type w) : Type w
  | zero : WalkingParallelFamily J
  | one : WalkingParallelFamily J
goal: CategoryTheory.Limits.WalkingParallelFamily J

full_name: CategoryTheory.Limits.instDecidableEqWalkingParallelFamily
code: instance : DecidableEq (WalkingParallelFamily J)
  
goal: DecidableEq (CategoryTheory.Limits.WalkingParallelFamily J)

full_name: CategoryTheory.Limits.instInhabitedWalkingParallelFamily
code: instance : Inhabited (WalkingParallelFamily J) 
goal: Inhabited (CategoryTheory.Limits.WalkingParallelFamily J)

full_name: CategoryTheory.Limits.WalkingParallelFamily.Hom.id
code: /-- The type family of morphisms for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily.Hom (J : Type w) :
  WalkingParallelFamily J → WalkingParallelFamily J → Type w
  | id : ∀ X : WalkingParallelFamily.{w} J, WalkingParallelFamily.Hom J X X
  | line : J → WalkingParallelFamily.Hom J zero one
  deriving DecidableEq
goal: CategoryTheory.Limits.WalkingParallelFamily.Hom J X X

full_name: CategoryTheory.Limits.WalkingParallelFamily.Hom
code: /-- The type family of morphisms for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily.Hom (J : Type w) :
  WalkingParallelFamily J → WalkingParallelFamily J → Type w
  | id : ∀ X : WalkingParallelFamily.{w} J, WalkingParallelFamily.Hom J X X
  | line : J → WalkingParallelFamily.Hom J zero one
  deriving DecidableEq
goal: CategoryTheory.Limits.WalkingParallelFamily J → CategoryTheory.Limits.WalkingParallelFamily J → Type w

full_name: CategoryTheory.Limits.WalkingParallelFamily.Hom.line
code: /-- The type family of morphisms for the diagram indexing a wide (co)equalizer. -/
inductive WalkingParallelFamily.Hom (J : Type w) :
  WalkingParallelFamily J → WalkingParallelFamily J → Type w
  | id : ∀ X : WalkingParallelFamily.{w} J, WalkingParallelFamily.Hom J X X
  | line : J → WalkingParallelFamily.Hom J zero one
  deriving DecidableEq
goal: J →
  CategoryTheory.Limits.WalkingParallelFamily.Hom J CategoryTheory.Limits.WalkingParallelFamily.zero
    CategoryTheory.Limits.WalkingParallelFamily.one

full_name: CategoryTheory.Limits.instInhabitedHomZero
code: /-- Satisfying the inhabited linter -/
instance (J : Type v) : Inhabited (WalkingParallelFamily.Hom J zero zero) 
goal: Inhabited
  (CategoryTheory.Limits.WalkingParallelFamily.Hom J CategoryTheory.Limits.WalkingParallelFamily.zero
    CategoryTheory.Limits.WalkingParallelFamily.zero)

full_name: CategoryTheory.Limits.WalkingParallelFamily.Hom.comp
code: /-- Composition of morphisms in the indexing diagram for wide (co)equalizers. -/
def WalkingParallelFamily.Hom.comp :
    ∀ {X Y Z : WalkingParallelFamily J} (_ : WalkingParallelFamily.Hom J X Y)
      (_ : WalkingParallelFamily.Hom J Y Z), WalkingParallelFamily.Hom J X Z
  
goal: CategoryTheory.Limits.WalkingParallelFamily.Hom J X Y →
  CategoryTheory.Limits.WalkingParallelFamily.Hom J Y Z → CategoryTheory.Limits.WalkingParallelFamily.Hom J X Z

full_name: CategoryTheory.Limits.WalkingParallelFamily.category
code: instance WalkingParallelFamily.category : SmallCategory (WalkingParallelFamily J) 
goal: CategoryTheory.SmallCategory (CategoryTheory.Limits.WalkingParallelFamily J)

full_name: CategoryTheory.Limits.WalkingParallelFamily.hom_id
code: @[simp]
theorem WalkingParallelFamily.hom_id (X : WalkingParallelFamily J) :
    WalkingParallelFamily.Hom.id X = 𝟙 X 
goal: CategoryTheory.Limits.WalkingParallelFamily.Hom.id X = CategoryTheory.CategoryStruct.id X

full_name: CategoryTheory.Limits.parallelFamily
code: /-- `parallelFamily f` is the diagram in `C` consisting of the given family of morphisms, each with
common domain and codomain.
-/
def parallelFamily : WalkingParallelFamily J ⥤ C 
goal: CategoryTheory.Functor (CategoryTheory.Limits.WalkingParallelFamily J) C

full_name: CategoryTheory.Limits.parallelFamily_obj_zero
code: @[simp]
theorem parallelFamily_obj_zero : (parallelFamily f).obj zero = X 
goal: (CategoryTheory.Limits.parallelFamily f).obj CategoryTheory.Limits.WalkingParallelFamily.zero = X

full_name: CategoryTheory.Limits.parallelFamily_obj_one
code: @[simp]
theorem parallelFamily_obj_one : (parallelFamily f).obj one = Y 
goal: (CategoryTheory.Limits.parallelFamily f).obj CategoryTheory.Limits.WalkingParallelFamily.one = Y

full_name: CategoryTheory.Limits.parallelFamily_map_left
code: @[simp]
theorem parallelFamily_map_left {j : J} : (parallelFamily f).map (line j) = f j 
goal: (CategoryTheory.Limits.parallelFamily f).map (CategoryTheory.Limits.WalkingParallelFamily.Hom.line j) = f j

full_name: CategoryTheory.Limits.diagramIsoParallelFamily_inv_app
code: /-- Every functor indexing a wide (co)equalizer is naturally isomorphic (actually, equal) to a
    `parallelFamily` -/
@[simps!]
def diagramIsoParallelFamily (F : WalkingParallelFamily J ⥤ C) :
    F ≅ parallelFamily fun j => F.map (line j) 
goal: (CategoryTheory.Limits.diagramIsoParallelFamily F).inv.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.diagramIsoParallelFamily_hom_app
code: /-- Every functor indexing a wide (co)equalizer is naturally isomorphic (actually, equal) to a
    `parallelFamily` -/
@[simps!]
def diagramIsoParallelFamily (F : WalkingParallelFamily J ⥤ C) :
    F ≅ parallelFamily fun j => F.map (line j) 
goal: (CategoryTheory.Limits.diagramIsoParallelFamily F).hom.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.diagramIsoParallelFamily
code: /-- Every functor indexing a wide (co)equalizer is naturally isomorphic (actually, equal) to a
    `parallelFamily` -/
@[simps!]
def diagramIsoParallelFamily (F : WalkingParallelFamily J ⥤ C) :
    F ≅ parallelFamily fun j => F.map (line j) 
goal: F ≅ CategoryTheory.Limits.parallelFamily fun j => F.map (CategoryTheory.Limits.WalkingParallelFamily.Hom.line j)

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_counitIso_hom_app
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.counitIso.hom.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_functor_map
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.functor.map h =
  match x, y, h with
  | x, .(x), CategoryTheory.Limits.WalkingParallelFamily.Hom.id .(x) =>
    CategoryTheory.CategoryStruct.id
      (CategoryTheory.Limits.WalkingParallelFamily.rec CategoryTheory.Limits.WalkingParallelPair.zero
        CategoryTheory.Limits.WalkingParallelPair.one x)
  | .(CategoryTheory.Limits.WalkingParallelFamily.zero), .(CategoryTheory.Limits.WalkingParallelFamily.one),
    CategoryTheory.Limits.WalkingParallelFamily.Hom.line j =>
    bif j.down then CategoryTheory.Limits.WalkingParallelPairHom.left
    else CategoryTheory.Limits.WalkingParallelPairHom.right

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.WalkingParallelFamily (ULift.{w, 0} Bool) ≌ CategoryTheory.Limits.WalkingParallelPair

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_counitIso_inv_app
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.counitIso.inv.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_unitIso_inv_app
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.unitIso.inv.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_inverse_obj
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.inverse.obj x =
  match x with
  | CategoryTheory.Limits.WalkingParallelPair.zero => CategoryTheory.Limits.WalkingParallelFamily.zero
  | CategoryTheory.Limits.WalkingParallelPair.one => CategoryTheory.Limits.WalkingParallelFamily.one

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_unitIso_hom_app
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.unitIso.hom.app X = CategoryTheory.eqToHom ⋯

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_functor_obj
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.functor.obj x =
  CategoryTheory.Limits.WalkingParallelFamily.rec CategoryTheory.Limits.WalkingParallelPair.zero
    CategoryTheory.Limits.WalkingParallelPair.one x

full_name: CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair_inverse_map
code: /-- `WalkingParallelPair` as a category is equivalent to a special case of
`WalkingParallelFamily`.  -/
@[simps!]
def walkingParallelFamilyEquivWalkingParallelPair :
    WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair 
goal: ∀ {X Y : CategoryTheory.Limits.WalkingParallelPair} (h : X ⟶ Y),
  CategoryTheory.Limits.walkingParallelFamilyEquivWalkingParallelPair.inverse.map h =
    match X, Y, h with
    | x, .(x), CategoryTheory.Limits.WalkingParallelPairHom.id .(x) =>
      CategoryTheory.CategoryStruct.id
        (match x with
        | CategoryTheory.Limits.WalkingParallelPair.zero => CategoryTheory.Limits.WalkingParallelFamily.zero
        | CategoryTheory.Limits.WalkingParallelPair.one => CategoryTheory.Limits.WalkingParallelFamily.one)
    | .(CategoryTheory.Limits.WalkingParallelPair.zero), .(CategoryTheory.Limits.WalkingParallelPair.one),
      CategoryTheory.Limits.WalkingParallelPairHom.left =>
      CategoryTheory.Limits.WalkingParallelFamily.Hom.line { down := true }
    | .(CategoryTheory.Limits.WalkingParallelPair.zero), .(CategoryTheory.Limits.WalkingParallelPair.one),
      CategoryTheory.Limits.WalkingParallelPairHom.right =>
      CategoryTheory.Limits.WalkingParallelFamily.Hom.line { down := false }

full_name: CategoryTheory.Limits.Trident
code: /-- A trident on `f` is just a `Cone (parallelFamily f)`. -/
abbrev Trident 
goal: Type (max (max w u) v)

full_name: CategoryTheory.Limits.Cotrident
code: /-- A cotrident on `f` and `g` is just a `Cocone (parallelFamily f)`. -/
abbrev Cotrident 
goal: Type (max (max w u) v)

full_name: CategoryTheory.Limits.Trident.ι
code: /-- A trident `t` on the parallel family `f : J → (X ⟶ Y)` consists of two morphisms
    `t.π.app zero : t.X ⟶ X` and `t.π.app one : t.X ⟶ Y`. Of these, only the first one is
    interesting, and we give it the shorter name `Trident.ι t`. -/
abbrev Trident.ι (t : Trident f) 
goal: ((CategoryTheory.Functor.const (CategoryTheory.Limits.WalkingParallelFamily J)).obj t.pt).obj
    CategoryTheory.Limits.WalkingParallelFamily.zero ⟶
  (CategoryTheory.Limits.parallelFamily f).obj CategoryTheory.Limits.WalkingParallelFamily.zero

full_name: CategoryTheory.Limits.Cotrident.π
code: /-- A cotrident `t` on the parallel family `f : J → (X ⟶ Y)` consists of two morphisms
    `t.ι.app zero : X ⟶ t.X` and `t.ι.app one : Y ⟶ t.X`. Of these, only the second one is
    interesting, and we give it the shorter name `Cotrident.π t`. -/
abbrev Cotrident.π (t : Cotrident f) 
goal: (CategoryTheory.Limits.parallelFamily f).obj CategoryTheory.Limits.WalkingParallelFamily.one ⟶
  ((CategoryTheory.Functor.const (CategoryTheory.Limits.WalkingParallelFamily J)).obj t.pt).obj
    CategoryTheory.Limits.WalkingParallelFamily.one

full_name: CategoryTheory.Limits.Trident.ι_eq_app_zero
code: @[simp]
theorem Trident.ι_eq_app_zero (t : Trident f) : t.ι = t.π.app zero 
goal: t.ι = t.π.app CategoryTheory.Limits.WalkingParallelFamily.zero

full_name: CategoryTheory.Limits.Cotrident.π_eq_app_one
code: @[simp]
theorem Cotrident.π_eq_app_one (t : Cotrident f) : t.π = t.ι.app one 
goal: t.π = t.ι.app CategoryTheory.Limits.WalkingParallelFamily.one

full_name: CategoryTheory.Limits.Trident.app_zero
code: @[reassoc (attr := simp)]
theorem Trident.app_zero (s : Trident f) (j : J) : s.π.app zero ≫ f j = s.π.app one 
goal: CategoryTheory.CategoryStruct.comp (s.π.app CategoryTheory.Limits.WalkingParallelFamily.zero) (f j) =
  s.π.app CategoryTheory.Limits.WalkingParallelFamily.one

full_name: CategoryTheory.Limits.Cotrident.app_one
code: @[reassoc (attr := simp)]
theorem Cotrident.app_one (s : Cotrident f) (j : J) : f j ≫ s.ι.app one = s.ι.app zero 
goal: CategoryTheory.CategoryStruct.comp (f j) (s.ι.app CategoryTheory.Limits.WalkingParallelFamily.one) =
  s.ι.app CategoryTheory.Limits.WalkingParallelFamily.zero

full_name: CategoryTheory.Limits.Trident.ofι
code: /-- 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 
goal: CategoryTheory.Limits.Trident f

full_name: CategoryTheory.Limits.Trident.ofι_π_app
code: /-- 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 
goal: ∀ (X_1 : CategoryTheory.Limits.WalkingParallelFamily J),
  (CategoryTheory.Limits.Trident.ofι ι w).π.app X_1 =
    CategoryTheory.Limits.WalkingParallelFamily.casesOn X_1 ι
      (CategoryTheory.CategoryStruct.comp ι (f (Classical.arbitrary J)))

full_name: CategoryTheory.Limits.Trident.ofι_pt
code: /-- 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 
goal: (CategoryTheory.Limits.Trident.ofι ι w).pt = P

full_name: CategoryTheory.Limits.Cotrident.ofπ_pt
code: /-- 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 
goal: (CategoryTheory.Limits.Cotrident.ofπ π w).pt = P

full_name: CategoryTheory.Limits.Cotrident.ofπ_ι_app
code: /-- 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 
goal: ∀ (X_1 : CategoryTheory.Limits.WalkingParallelFamily J),
  (CategoryTheory.Limits.Cotrident.ofπ π w).ι.app X_1 =
    CategoryTheory.Limits.WalkingParallelFamily.casesOn X_1
      (CategoryTheory.CategoryStruct.comp (f (Classical.arbitrary J)) π) π

full_name: CategoryTheory.Limits.Cotrident.ofπ
code: /-- 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 
goal: CategoryTheory.Limits.Cotrident f

full_name: CategoryTheory.Limits.Trident.ι_ofι
code: theorem Trident.ι_ofι [Nonempty J] {P : C} (ι : P ⟶ X) (w : ∀ j₁ j₂, ι ≫ f j₁ = ι ≫ f j₂) :
    (Trident.ofι ι w).ι = ι 
goal: (CategoryTheory.Limits.Trident.ofι ι w).ι = ι

full_name: CategoryTheory.Limits.Cotrident.π_ofπ
code: theorem Cotrident.π_ofπ [Nonempty J] {P : C} (π : Y ⟶ P) (w : ∀ j₁ j₂, f j₁ ≫ π = f j₂ ≫ π) :
    (Cotrident.ofπ π w).π = π 
goal: (CategoryTheory.Limits.Cotrident.ofπ π w).π = π

full_name: CategoryTheory.Limits.Trident.condition
code: @[reassoc]
theorem Trident.condition (j₁ j₂ : J) (t : Trident f) : t.ι ≫ f j₁ = t.ι ≫ f j₂ 
goal: CategoryTheory.CategoryStruct.comp t.ι (f j₁) = CategoryTheory.CategoryStruct.comp t.ι (f j₂)

full_name: CategoryTheory.Limits.Cotrident.condition
code: @[reassoc]
theorem Cotrident.condition (j₁ j₂ : J) (t : Cotrident f) : f j₁ ≫ t.π = f j₂ ≫ t.π 
goal: CategoryTheory.CategoryStruct.comp (f j₁) t.π = CategoryTheory.CategoryStruct.comp (f j₂) t.π

full_name: CategoryTheory.Limits.Trident.equalizer_ext
code: /-- 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
  
goal: CategoryTheory.CategoryStruct.comp k (s.π.app j) = CategoryTheory.CategoryStruct.comp l (s.π.app j)

full_name: CategoryTheory.Limits.Cotrident.coequalizer_ext
code: /-- 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
  
goal: CategoryTheory.CategoryStruct.comp (s.ι.app j) k = CategoryTheory.CategoryStruct.comp (s.ι.app j) l

full_name: CategoryTheory.Limits.Trident.IsLimit.hom_ext
code: theorem Trident.IsLimit.hom_ext [Nonempty J] {s : Trident f} (hs : IsLimit s) {W : C}
    {k l : W ⟶ s.pt} (h : k ≫ s.ι = l ≫ s.ι) : k = l 
goal: k = l

full_name: CategoryTheory.Limits.Cotrident.IsColimit.hom_ext
code: theorem Cotrident.IsColimit.hom_ext [Nonempty J] {s : Cotrident f} (hs : IsColimit s) {W : C}
    {k l : s.pt ⟶ W} (h : s.π ≫ k = s.π ≫ l) : k = l 
goal: k = l

full_name: CategoryTheory.Limits.Trident.IsLimit.lift'
code: /-- If `s` is a limit trident over `f`, then a morphism `k : W ⟶ X` satisfying
    `∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂` induces a morphism `l : W ⟶ s.X` such that
    `l ≫ Trident.ι s = k`. -/
def Trident.IsLimit.lift' [Nonempty J] {s : Trident f} (hs : IsLimit s) {W : C} (k : W ⟶ X)
    (h : ∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂) : { l : W ⟶ s.pt // l ≫ Trident.ι s = k } 
goal: { l // CategoryTheory.CategoryStruct.comp l s.ι = k }

full_name: CategoryTheory.Limits.Cotrident.IsColimit.desc'
code: /-- If `s` is a colimit cotrident over `f`, then a morphism `k : Y ⟶ W` satisfying
    `∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k` induces a morphism `l : s.X ⟶ W` such that
    `Cotrident.π s ≫ l = k`. -/
def Cotrident.IsColimit.desc' [Nonempty J] {s : Cotrident f} (hs : IsColimit s) {W : C} (k : Y ⟶ W)
    (h : ∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k) : { l : s.pt ⟶ W // Cotrident.π s ≫ l = k } 
goal: { l // CategoryTheory.CategoryStruct.comp s.π l = k }

full_name: CategoryTheory.Limits.Trident.IsLimit.mk
code: /-- 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 
goal: CategoryTheory.Limits.IsLimit t

full_name: CategoryTheory.Limits.Trident.IsLimit.mk'
code: /-- This is another convenient method to verify that a trident is a limit cone. It
    only asks for a proof of facts that carry any mathematical content, and allows access to the
    same `s` for all parts. -/
def Trident.IsLimit.mk' [Nonempty J] (t : Trident f)
    (create : ∀ s : Trident f, { l // l ≫ t.ι = s.ι ∧ ∀ {m}, m ≫ t.ι = s.ι → m = l }) :
    IsLimit t 
goal: CategoryTheory.Limits.IsLimit t

full_name: CategoryTheory.Limits.Cotrident.IsColimit.mk
code: /-- 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 
goal: CategoryTheory.Limits.IsColimit t

full_name: CategoryTheory.Limits.Cotrident.IsColimit.mk'
code: /-- This is another convenient method to verify that a cotrident is a colimit cocone. It
    only asks for a proof of facts that carry any mathematical content, and allows access to the
    same `s` for all parts. -/
def Cotrident.IsColimit.mk' [Nonempty J] (t : Cotrident f)
    (create :
      ∀ s : Cotrident f, { l : t.pt ⟶ s.pt // t.π ≫ l = s.π ∧ ∀ {m}, t.π ≫ m = s.π → m = l }) :
    IsColimit t 
goal: CategoryTheory.Limits.IsColimit t

full_name: CategoryTheory.Limits.Trident.IsLimit.homIso
code: /--
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₂ } 
goal: (Z ⟶ t.pt) ≃
  { h // ∀ (j₁ j₂ : J), CategoryTheory.CategoryStruct.comp h (f j₁) = CategoryTheory.CategoryStruct.comp h (f j₂) }

full_name: CategoryTheory.Limits.Trident.IsLimit.homIso_symm_apply
code: /--
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₂ } 
goal: (CategoryTheory.Limits.Trident.IsLimit.homIso ht Z).symm h = ↑(CategoryTheory.Limits.Trident.IsLimit.lift' ht ↑h ⋯)

full_name: CategoryTheory.Limits.Trident.IsLimit.homIso_apply_coe
code: /--
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₂ } 
goal: ↑((CategoryTheory.Limits.Trident.IsLimit.homIso ht Z) k) = CategoryTheory.CategoryStruct.comp k t.ι

full_name: CategoryTheory.Limits.Trident.IsLimit.homIso_natural
code: /-- The bijection of `Trident.IsLimit.homIso` is natural in `Z`. -/
theorem Trident.IsLimit.homIso_natural [Nonempty J] {t : Trident f} (ht : IsLimit t) {Z Z' : C}
    (q : Z' ⟶ Z) (k : Z ⟶ t.pt) :
    (Trident.IsLimit.homIso ht _ (q ≫ k) : Z' ⟶ X) =
      q ≫ (Trident.IsLimit.homIso ht _ k : Z ⟶ X) 
goal: ↑((CategoryTheory.Limits.Trident.IsLimit.homIso ht Z') (CategoryTheory.CategoryStruct.comp q k)) =
  CategoryTheory.CategoryStruct.comp q ↑((CategoryTheory.Limits.Trident.IsLimit.homIso ht Z) k)

full_name: CategoryTheory.Limits.Cotrident.IsColimit.homIso_apply_coe
code: /-- 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 } 
goal: ↑((CategoryTheory.Limits.Cotrident.IsColimit.homIso ht Z) k) = CategoryTheory.CategoryStruct.comp t.π k

full_name: CategoryTheory.Limits.Cotrident.IsColimit.homIso_symm_apply
code: /-- 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 } 
goal: (CategoryTheory.Limits.Cotrident.IsColimit.homIso ht Z).symm h =
  ↑(CategoryTheory.Limits.Cotrident.IsColimit.desc' ht ↑h ⋯)

full_name: CategoryTheory.Limits.Cotrident.IsColimit.homIso
code: /-- 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 } 
goal: (t.pt ⟶ Z) ≃
  { h // ∀ (j₁ j₂ : J), CategoryTheory.CategoryStruct.comp (f j₁) h = CategoryTheory.CategoryStruct.comp (f j₂) h }

full_name: CategoryTheory.Limits.Cotrident.IsColimit.homIso_natural
code: /-- The bijection of `Cotrident.IsColimit.homIso` is natural in `Z`. -/
theorem Cotrident.IsColimit.homIso_natural [Nonempty J] {t : Cotrident f} {Z Z' : C} (q : Z ⟶ Z')
    (ht : IsColimit t) (k : t.pt ⟶ Z) :
    (Cotrident.IsColimit.homIso ht _ (k ≫ q) : Y ⟶ Z') =
      (Cotrident.IsColimit.homIso ht _ k : Y ⟶ Z) ≫ q 
goal: ↑((CategoryTheory.Limits.Cotrident.IsColimit.homIso ht Z') (CategoryTheory.CategoryStruct.comp k q)) =
  CategoryTheory.CategoryStruct.comp (↑((CategoryTheory.Limits.Cotrident.IsColimit.homIso ht Z) k)) q

full_name: CategoryTheory.Limits.Cone.ofTrident
code: /-- 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 (fun j ↦ F.map (line j))`, and a trident on `fun 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 
goal: CategoryTheory.Limits.Cone F

full_name: CategoryTheory.Limits.Cocone.ofCotrident
code: /-- This is a helper construction that can be useful when verifying that a category has all
    coequalizers. Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (fun j ↦ F.map (line j))`, and a cotrident on `fun j ↦ F.map (line j)` we get a
    cocone on `F`.

    If you're thinking about using this, have a look at
    `hasWideCoequalizers_of_hasColimit_parallelFamily`, which you may find to be an easier way
    of achieving your goal. -/
def Cocone.ofCotrident {F : WalkingParallelFamily J ⥤ C} (t : Cotrident fun j => F.map (line j)) :
    Cocone F 
goal: CategoryTheory.Limits.Cocone F

full_name: CategoryTheory.Limits.Cone.ofTrident_π
code: @[simp]
theorem Cone.ofTrident_π {F : WalkingParallelFamily J ⥤ C} (t : Trident fun j => F.map (line j))
    (j) : (Cone.ofTrident t).π.app j = t.π.app j ≫ eqToHom (by cases j <;> aesop_cat) 
goal: (CategoryTheory.Limits.Cone.ofTrident t).π.app j =
  CategoryTheory.CategoryStruct.comp (t.π.app j) (CategoryTheory.eqToHom ⋯)

full_name: CategoryTheory.Limits.Cocone.ofCotrident_ι
code: @[simp]
theorem Cocone.ofCotrident_ι {F : WalkingParallelFamily J ⥤ C}
    (t : Cotrident fun j => F.map (line j)) (j) :
    (Cocone.ofCotrident t).ι.app j = eqToHom (by cases j <;> aesop_cat) ≫ t.ι.app j 
goal: (CategoryTheory.Limits.Cocone.ofCotrident t).ι.app j =
  CategoryTheory.CategoryStruct.comp (CategoryTheory.eqToHom ⋯) (t.ι.app j)

full_name: CategoryTheory.Limits.Trident.ofCone
code: /-- Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (fun j ↦ F.map (line j))` and a cone on `F`, we get a trident on
    `fun j ↦ F.map (line j)`. -/
def Trident.ofCone {F : WalkingParallelFamily J ⥤ C} (t : Cone F) :
    Trident fun j => F.map (line j) 
goal: CategoryTheory.Limits.Trident fun j => F.map (CategoryTheory.Limits.WalkingParallelFamily.Hom.line j)

full_name: CategoryTheory.Limits.Cotrident.ofCocone
code: /-- Given `F : WalkingParallelFamily ⥤ C`, which is really the same as
    `parallelFamily (F.map left) (F.map right)` and a cocone on `F`, we get a cotrident on
    `fun j ↦ F.map (line j)`. -/
def Cotrident.ofCocone {F : WalkingParallelFamily J ⥤ C} (t : Cocone F) :
    Cotrident fun j => F.map (line j) 
goal: CategoryTheory.Limits.Cotrident fun j => F.map (CategoryTheory.Limits.WalkingParallelFamily.Hom.line j)

full_name: CategoryTheory.Limits.Trident.ofCone_π
code: @[simp]
theorem Trident.ofCone_π {F : WalkingParallelFamily J ⥤ C} (t : Cone F) (j) :
    (Trident.ofCone t).π.app j = t.π.app j ≫ eqToHom (by cases j <;> aesop_cat) 
goal: (CategoryTheory.Limits.Trident.ofCone t).π.app j =
  CategoryTheory.CategoryStruct.comp (t.π.app j) (CategoryTheory.eqToHom ⋯)

full_name: CategoryTheory.Limits.Cotrident.ofCocone_ι
code: @[simp]
theorem Cotrident.ofCocone_ι {F : WalkingParallelFamily J ⥤ C} (t : Cocone F) (j) :
    (Cotrident.ofCocone t).ι.app j = eqToHom (by cases j <;> aesop_cat) ≫ t.ι.app j 
goal: (CategoryTheory.Limits.Cotrident.ofCocone t).ι.app j =
  CategoryTheory.CategoryStruct.comp (CategoryTheory.eqToHom ⋯) (t.ι.app j)

full_name: CategoryTheory.Limits.Trident.mkHom_hom
code: /-- Helper function for constructing morphisms between wide equalizer tridents.
-/
@[simps]
def Trident.mkHom [Nonempty J] {s t : Trident f} (k : s.pt ⟶ t.pt)
    (w : k ≫ t.ι = s.ι := by aesop_cat) : s ⟶ t 
goal: (CategoryTheory.Limits.Trident.mkHom k w).hom = k

full_name: CategoryTheory.Limits.Trident.mkHom
code: /-- Helper function for constructing morphisms between wide equalizer tridents.
-/
@[simps]
def Trident.mkHom [Nonempty J] {s t : Trident f} (k : s.pt ⟶ t.pt)
    (w : k ≫ t.ι = s.ι := by aesop_cat) : s ⟶ t 
goal: s ⟶ t

full_name: CategoryTheory.Limits.Trident.ext
code: /-- To construct an isomorphism between tridents,
it suffices to give an isomorphism between the cone points
and check that it commutes with the `ι` morphisms.
-/
@[simps]
def Trident.ext [Nonempty J] {s t : Trident f} (i : s.pt ≅ t.pt)
    (w : i.hom ≫ t.ι = s.ι := by aesop_cat) : s ≅ t 
goal: s ≅ t

full_name: CategoryTheory.Limits.Trident.ext_hom
code: /-- To construct an isomorphism between tridents,
it suffices to give an isomorphism between the cone points
and check that it commutes with the `ι` morphisms.
-/
@[simps]
def Trident.ext [Nonempty J] {s t : Trident f} (i : s.pt ≅ t.pt)
    (w : i.hom ≫ t.ι = s.ι := by aesop_cat) : s ≅ t 
goal: (CategoryTheory.Limits.Trident.ext i w).hom = CategoryTheory.Limits.Trident.mkHom i.hom w

full_name: CategoryTheory.Limits.Trident.ext_inv
code: /-- To construct an isomorphism between tridents,
it suffices to give an isomorphism between the cone points
and check that it commutes with the `ι` morphisms.
-/
@[simps]
def Trident.ext [Nonempty J] {s t : Trident f} (i : s.pt ≅ t.pt)
    (w : i.hom ≫ t.ι = s.ι := by aesop_cat) : s ≅ t 
goal: (CategoryTheory.Limits.Trident.ext i w).inv = CategoryTheory.Limits.Trident.mkHom i.inv ⋯

full_name: CategoryTheory.Limits.Cotrident.mkHom_hom
code: /-- Helper function for constructing morphisms between coequalizer cotridents.
-/
@[simps]
def Cotrident.mkHom [Nonempty J] {s t : Cotrident f} (k : s.pt ⟶ t.pt)
    (w : s.π ≫ k = t.π := by aesop_cat) : s ⟶ t 
goal: (CategoryTheory.Limits.Cotrident.mkHom k w).hom = k

full_name: CategoryTheory.Limits.Cotrident.mkHom
code: /-- Helper function for constructing morphisms between coequalizer cotridents.
-/
@[simps]
def Cotrident.mkHom [Nonempty J] {s t : Cotrident f} (k : s.pt ⟶ t.pt)
    (w : s.π ≫ k = t.π := by aesop_cat) : s ⟶ t 
goal: s ⟶ t

full_name: CategoryTheory.Limits.Cotrident.ext
code: /-- To construct an isomorphism between cotridents,
it suffices to give an isomorphism between the cocone points
and check that it commutes with the `π` morphisms.
-/
def Cotrident.ext [Nonempty J] {s t : Cotrident f} (i : s.pt ≅ t.pt)
    (w : s.π ≫ i.hom = t.π := by aesop_cat) : s ≅ t 
goal: s ≅ t

full_name: CategoryTheory.Limits.HasWideEqualizer
code: /--
`HasWideEqualizer f` represents a particular choice of limiting cone for the parallel family of
morphisms `f`.
-/
abbrev HasWideEqualizer 
goal: Prop

full_name: CategoryTheory.Limits.wideEqualizer
code: /-- If a wide equalizer of `f` exists, we can access an arbitrary choice of such by
    saying `wideEqualizer f`. -/
abbrev wideEqualizer : C 
goal: C

full_name: CategoryTheory.Limits.wideEqualizer.ι
code: /-- If a wide equalizer of `f` exists, we can access the inclusion `wideEqualizer f ⟶ X` by
    saying `wideEqualizer.ι f`. -/
abbrev wideEqualizer.ι : wideEqualizer f ⟶ X 
goal: CategoryTheory.Limits.wideEqualizer f ⟶ X

full_name: CategoryTheory.Limits.wideEqualizer.trident
code: /-- A wide equalizer cone for a parallel family `f`.
-/
abbrev wideEqualizer.trident : Trident f 
goal: CategoryTheory.Limits.Trident f

full_name: CategoryTheory.Limits.wideEqualizer.trident_ι
code: @[simp]
theorem wideEqualizer.trident_ι : (wideEqualizer.trident f).ι = wideEqualizer.ι f 
goal: (CategoryTheory.Limits.wideEqualizer.trident f).ι = CategoryTheory.Limits.wideEqualizer.ι f

full_name: CategoryTheory.Limits.wideEqualizer.trident_π_app_zero
code: @[simp 1100]
theorem wideEqualizer.trident_π_app_zero :
    (wideEqualizer.trident f).π.app zero = wideEqualizer.ι f 
goal: (CategoryTheory.Limits.wideEqualizer.trident f).π.app CategoryTheory.Limits.WalkingParallelFamily.zero =
  CategoryTheory.Limits.wideEqualizer.ι f

full_name: CategoryTheory.Limits.wideEqualizer.condition
code: @[reassoc]
theorem wideEqualizer.condition (j₁ j₂ : J) : wideEqualizer.ι f ≫ f j₁ = wideEqualizer.ι f ≫ f j₂ 
goal: CategoryTheory.CategoryStruct.comp (CategoryTheory.Limits.wideEqualizer.ι f) (f j₁) =
  CategoryTheory.CategoryStruct.comp (CategoryTheory.Limits.wideEqualizer.ι f) (f j₂)

full_name: CategoryTheory.Limits.wideEqualizerIsWideEqualizer
code: /-- The wideEqualizer built from `wideEqualizer.ι f` is limiting. -/
def wideEqualizerIsWideEqualizer [Nonempty J] :
    IsLimit (Trident.ofι (wideEqualizer.ι f) (wideEqualizer.condition f)) 
goal: CategoryTheory.Limits.IsLimit (CategoryTheory.Limits.Trident.ofι (CategoryTheory.Limits.wideEqualizer.ι f) ⋯)

full_name: CategoryTheory.Limits.wideEqualizer.lift
code: /-- A morphism `k : W ⟶ X` satisfying `∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂` factors through the
    wide equalizer of `f` via `wideEqualizer.lift : W ⟶ wideEqualizer f`. -/
abbrev wideEqualizer.lift [Nonempty J] {W : C} (k : W ⟶ X) (h : ∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂) :
    W ⟶ wideEqualizer f 
goal: W ⟶ CategoryTheory.Limits.wideEqualizer f

full_name: CategoryTheory.Limits.wideEqualizer.lift_ι
code: @[reassoc (attr := simp 1100)]
theorem wideEqualizer.lift_ι [Nonempty J] {W : C} (k : W ⟶ X)
    (h : ∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂) :
    wideEqualizer.lift k h ≫ wideEqualizer.ι f = k 
goal: CategoryTheory.CategoryStruct.comp (CategoryTheory.Limits.wideEqualizer.lift k h)
    (CategoryTheory.Limits.wideEqualizer.ι f) =
  k

full_name: CategoryTheory.Limits.wideEqualizer.lift'
code: /-- A morphism `k : W ⟶ X` satisfying `∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂` induces a morphism
    `l : W ⟶ wideEqualizer f` satisfying `l ≫ wideEqualizer.ι f = k`. -/
def wideEqualizer.lift' [Nonempty J] {W : C} (k : W ⟶ X) (h : ∀ j₁ j₂, k ≫ f j₁ = k ≫ f j₂) :
    { l : W ⟶ wideEqualizer f // l ≫ wideEqualizer.ι f = k } 
goal: { l // CategoryTheory.CategoryStruct.comp l (CategoryTheory.Limits.wideEqualizer.ι f) = k }

full_name: CategoryTheory.Limits.wideEqualizer.hom_ext
code: /-- Two maps into a wide equalizer are equal if they are equal when composed with the wide
    equalizer map. -/
@[ext]
theorem wideEqualizer.hom_ext [Nonempty J] {W : C} {k l : W ⟶ wideEqualizer f}
    (h : k ≫ wideEqualizer.ι f = l ≫ wideEqualizer.ι f) : k = l 
goal: k = l

full_name: CategoryTheory.Limits.wideEqualizer.ι_mono
code: /-- A wide equalizer morphism is a monomorphism -/
instance wideEqualizer.ι_mono [Nonempty J] : Mono (wideEqualizer.ι f) 
goal: CategoryTheory.Mono (CategoryTheory.Limits.wideEqualizer.ι f)

full_name: CategoryTheory.Limits.mono_of_isLimit_parallelFamily
code: /-- The wide equalizer morphism in any limit cone is a monomorphism. -/
theorem mono_of_isLimit_parallelFamily [Nonempty J] {c : Cone (parallelFamily f)} (i : IsLimit c) :
    Mono (Trident.ι c) 
goal: CategoryTheory.Mono (CategoryTheory.Limits.Trident.ι c)

full_name: CategoryTheory.Limits.HasWideCoequalizer
code: /-- `HasWideCoequalizer f g` represents a particular choice of colimiting cocone
for the parallel family of morphisms `f`.
-/
abbrev HasWideCoequalizer 
goal: Prop

full_name: CategoryTheory.Limits.wideCoequalizer
code: /-- If a wide coequalizer of `f`, we can access an arbitrary choice of such by
    saying `wideCoequalizer f`. -/
abbrev wideCoequalizer : C 
goal: C

full_name: CategoryTheory.Limits.wideCoequalizer.π
code: /-- If a wideCoequalizer of `f` exists, we can access the corresponding projection by
    saying `wideCoequalizer.π f`. -/
abbrev wideCoequalizer.π : Y ⟶ wideCoequalizer f 
goal: Y ⟶ CategoryTheory.Limits.wideCoequalizer f

full_name: CategoryTheory.Limits.wideCoequalizer.cotrident
code: /-- An arbitrary choice of coequalizer cocone for a parallel family `f`.
-/
abbrev wideCoequalizer.cotrident : Cotrident f 
goal: CategoryTheory.Limits.Cotrident f

full_name: CategoryTheory.Limits.wideCoequalizer.cotrident_π
code: @[simp]
theorem wideCoequalizer.cotrident_π : (wideCoequalizer.cotrident f).π = wideCoequalizer.π f 
goal: (CategoryTheory.Limits.wideCoequalizer.cotrident f).π = CategoryTheory.Limits.wideCoequalizer.π f

full_name: CategoryTheory.Limits.wideCoequalizer.cotrident_ι_app_one
code: @[simp 1100]
theorem wideCoequalizer.cotrident_ι_app_one :
    (wideCoequalizer.cotrident f).ι.app one = wideCoequalizer.π f 
goal: (CategoryTheory.Limits.wideCoequalizer.cotrident f).ι.app CategoryTheory.Limits.WalkingParallelFamily.one =
  CategoryTheory.Limits.wideCoequalizer.π f

full_name: CategoryTheory.Limits.wideCoequalizer.condition
code: @[reassoc]
theorem wideCoequalizer.condition (j₁ j₂ : J) :
    f j₁ ≫ wideCoequalizer.π f = f j₂ ≫ wideCoequalizer.π f 
goal: CategoryTheory.CategoryStruct.comp (f j₁) (CategoryTheory.Limits.wideCoequalizer.π f) =
  CategoryTheory.CategoryStruct.comp (f j₂) (CategoryTheory.Limits.wideCoequalizer.π f)

full_name: CategoryTheory.Limits.wideCoequalizerIsWideCoequalizer
code: /-- The cotrident built from `wideCoequalizer.π f` is colimiting. -/
def wideCoequalizerIsWideCoequalizer [Nonempty J] :
    IsColimit (Cotrident.ofπ (wideCoequalizer.π f) (wideCoequalizer.condition f)) 
goal: CategoryTheory.Limits.IsColimit (CategoryTheory.Limits.Cotrident.ofπ (CategoryTheory.Limits.wideCoequalizer.π f) ⋯)

full_name: CategoryTheory.Limits.wideCoequalizer.desc
code: /-- Any morphism `k : Y ⟶ W` satisfying `∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k` factors through the
    wide coequalizer of `f` via `wideCoequalizer.desc : wideCoequalizer f ⟶ W`. -/
abbrev wideCoequalizer.desc [Nonempty J] {W : C} (k : Y ⟶ W) (h : ∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k) :
    wideCoequalizer f ⟶ W 
goal: CategoryTheory.Limits.wideCoequalizer f ⟶ W

full_name: CategoryTheory.Limits.wideCoequalizer.π_desc
code: @[reassoc (attr := simp 1100)]
theorem wideCoequalizer.π_desc [Nonempty J] {W : C} (k : Y ⟶ W)
    (h : ∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k) :
    wideCoequalizer.π f ≫ wideCoequalizer.desc k h = k 
goal: CategoryTheory.CategoryStruct.comp (CategoryTheory.Limits.wideCoequalizer.π f)
    (CategoryTheory.Limits.wideCoequalizer.desc k h) =
  k

full_name: CategoryTheory.Limits.wideCoequalizer.desc'
code: /-- Any morphism `k : Y ⟶ W` satisfying `∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k` induces a morphism
    `l : wideCoequalizer f ⟶ W` satisfying `wideCoequalizer.π ≫ g = l`. -/
def wideCoequalizer.desc' [Nonempty J] {W : C} (k : Y ⟶ W) (h : ∀ j₁ j₂, f j₁ ≫ k = f j₂ ≫ k) :
    { l : wideCoequalizer f ⟶ W // wideCoequalizer.π f ≫ l = k } 
goal: { l // CategoryTheory.CategoryStruct.comp (CategoryTheory.Limits.wideCoequalizer.π f) l = k }

full_name: CategoryTheory.Limits.wideCoequalizer.hom_ext
code: /-- Two maps from a wide coequalizer are equal if they are equal when composed with the wide
    coequalizer map -/
@[ext]
theorem wideCoequalizer.hom_ext [Nonempty J] {W : C} {k l : wideCoequalizer f ⟶ W}
    (h : wideCoequalizer.π f ≫ k = wideCoequalizer.π f ≫ l) : k = l 
goal: k = l

full_name: CategoryTheory.Limits.wideCoequalizer.π_epi
code: /-- A wide coequalizer morphism is an epimorphism -/
instance wideCoequalizer.π_epi [Nonempty J] : Epi (wideCoequalizer.π f) 
goal: CategoryTheory.Epi (CategoryTheory.Limits.wideCoequalizer.π f)

full_name: CategoryTheory.Limits.epi_of_isColimit_parallelFamily
code: /-- The wide coequalizer morphism in any colimit cocone is an epimorphism. -/
theorem epi_of_isColimit_parallelFamily [Nonempty J] {c : Cocone (parallelFamily f)}
    (i : IsColimit c) : Epi (c.ι.app one) 
goal: CategoryTheory.Epi (c.ι.app CategoryTheory.Limits.WalkingParallelFamily.one)

full_name: CategoryTheory.Limits.HasWideEqualizers
code: /-- `HasWideEqualizers` represents a choice of wide equalizer for every family of morphisms -/
abbrev HasWideEqualizers 
goal: Prop

full_name: CategoryTheory.Limits.HasWideCoequalizers
code: /-- `HasWideCoequalizers` represents a choice of wide coequalizer for every family of morphisms -/
abbrev HasWideCoequalizers 
goal: Prop

full_name: CategoryTheory.Limits.hasWideEqualizers_of_hasLimit_parallelFamily
code: /-- If `C` has all limits of diagrams `parallelFamily f`, then it has all wide equalizers -/
theorem hasWideEqualizers_of_hasLimit_parallelFamily
    [∀ {J : Type w} {X Y : C} {f : J → (X ⟶ Y)}, HasLimit (parallelFamily f)] :
    HasWideEqualizers.{w} C 
goal: CategoryTheory.Limits.HasWideEqualizers C

full_name: CategoryTheory.Limits.hasWideCoequalizers_of_hasColimit_parallelFamily
code: /-- If `C` has all colimits of diagrams `parallelFamily f`, then it has all wide coequalizers -/
theorem hasWideCoequalizers_of_hasColimit_parallelFamily
    [∀ {J : Type w} {X Y : C} {f : J → (X ⟶ Y)}, HasColimit (parallelFamily f)] :
    HasWideCoequalizers.{w} C 
goal: CategoryTheory.Limits.HasWideCoequalizers C

full_name: CategoryTheory.Limits.hasEqualizers_of_hasWideEqualizers
code: instance (priority := 10) hasEqualizers_of_hasWideEqualizers [HasWideEqualizers.{w} C] :
    HasEqualizers C 
goal: CategoryTheory.Limits.HasEqualizers C

full_name: CategoryTheory.Limits.hasCoequalizers_of_hasWideCoequalizers
code: instance (priority := 10) hasCoequalizers_of_hasWideCoequalizers [HasWideCoequalizers.{w} C] :
    HasCoequalizers C 
goal: CategoryTheory.Limits.HasCoequalizers C