l3lab/ntp-mathlib huggingface dataset:
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      

Proof state:
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
⊢ m =
    IsColimit.desc Hf
      { pt := W, ι := NatTrans.mk fun x => Exists.choose (_ : (Sieve.generateSingleton f).arrows x.obj.hom) ≫ e }

Next tactic:
apply Hf.uniq (aux e h)
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      

Proof state:
case x
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
⊢ ∀ (j : FullSubcategory fun f_1 => (Sieve.generateSingleton f).arrows f_1.hom),
    (Presieve.cocone (Sieve.generateSingleton f).arrows).ι.app j ≫ m =
      (aux e (_ : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e)).ι.app j

Next tactic:
rintro ⟨A,g,hA⟩
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      rintro ⟨A,g,hA⟩
      

Proof state:
case x.mk.intro
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
A : Over X
g : (𝟭 C).obj A.left ⟶ Y
hA : g ≫ f = A.hom
⊢ (Presieve.cocone (Sieve.generateSingleton f).arrows).ι.app { obj := A, property := (_ : ∃ e, e ≫ f = A.hom) } ≫ m =
    (aux e (_ : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e)).ι.app
      { obj := A, property := (_ : ∃ e, e ≫ f = A.hom) }

Next tactic:
dsimp
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      rintro ⟨A,g,hA⟩
      dsimp
      

Proof state:
case x.mk.intro
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
A : Over X
g : (𝟭 C).obj A.left ⟶ Y
hA : g ≫ f = A.hom
⊢ A.hom ≫ m = Exists.choose (_ : ∃ e, e ≫ f = A.hom) ≫ e

Next tactic:
nth_rewrite 1 [← hA, Category.assoc, hm]
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      rintro ⟨A,g,hA⟩
      dsimp
      nth_rewrite 1 [← hA, Category.assoc, hm]
      

Proof state:
case x.mk.intro
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
A : Over X
g : (𝟭 C).obj A.left ⟶ Y
hA : g ≫ f = A.hom
⊢ g ≫ e = Exists.choose (_ : ∃ e, e ≫ f = A.hom) ≫ e

Next tactic:
apply h
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      rintro ⟨A,g,hA⟩
      dsimp
      nth_rewrite 1 [← hA, Category.assoc, hm]
      apply h
      

Proof state:
case x.mk.intro.a
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
A : Over X
g : (𝟭 C).obj A.left ⟶ Y
hA : g ≫ f = A.hom
⊢ g ≫ f = Exists.choose (_ : ∃ e, e ≫ f = A.hom) ≫ f

Next tactic:
generalize_proofs hh
/--
Implementation: This is a construction which will be used in the proof that
the sieve generated by a single arrow is effective epimorphic if and only if
the arrow is an effective epi.
-/
noncomputable
def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X)
    (Hf : IsColimit (Sieve.generateSingleton f : Presieve X).cocone) :
    EffectiveEpiStruct f :=
  let aux {W : C} (e : Y ⟶ W)
    (h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) :
    Cocone (Sieve.generateSingleton f).arrows.diagram :=
    { pt := W
      ι := {
        app := fun ⟨T,hT⟩ => hT.choose ≫ e
        naturality := by
          rintro ⟨A,hA⟩ ⟨B,hB⟩ (q : A ⟶ B)
          dsimp; simp only [← Category.assoc, Category.comp_id]
          apply h
          rw [Category.assoc, hB.choose_spec, hA.choose_spec, Over.w] } }
  { desc := fun {W} e h => Hf.desc (aux e h)
    fac := by
      intro W e h
      dsimp
      have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩
      dsimp at this; rw [this]; clear this
      nth_rewrite 2 [← Category.id_comp e]
      apply h
      generalize_proofs hh
      rw [hh.choose_spec, Category.id_comp]
    uniq := by
      intro W e h m hm
      dsimp
      apply Hf.uniq (aux e h)
      rintro ⟨A,g,hA⟩
      dsimp
      nth_rewrite 1 [← hA, Category.assoc, hm]
      apply h
      generalize_proofs hh
      

Proof state:
case x.mk.intro.a
C : Type u_1
inst✝ : Category.{?u.21354, u_1} C
X Y : C
f : Y ⟶ X
Hf : IsColimit (Presieve.cocone (Sieve.generateSingleton f).arrows)
aux : {W : C} →
  (e : Y ⟶ W) →
    (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) →
      Cocone (Presieve.diagram (Sieve.generateSingleton f).arrows) :=
  fun {W} e h =>
    { pt := W,
      ι :=
        NatTrans.mk fun x =>
          match x with
          | { obj := T, property := hT } => Exists.choose hT ≫ e }
W : C
e : Y ⟶ W
h : ∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e
m : X ⟶ W
hm : f ≫ m = e
A : Over X
g : (𝟭 C).obj A.left ⟶ Y
hA : g ≫ f = A.hom
hh : ∃ e, e ≫ f = A.hom
⊢ g ≫ f = Exists.choose hh ≫ f

Next tactic:
rwa [hh.choose_spec]
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
⊢ Presieve.EffectiveEpimorphic (Presieve.singleton f) ↔ EffectiveEpi f

Next tactic:
constructor
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · 

Proof state:
case mp
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
⊢ Presieve.EffectiveEpimorphic (Presieve.singleton f) → EffectiveEpi f

Next tactic:
intro (h : Nonempty _)
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    

Proof state:
case mp
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (IsColimit (Presieve.cocone (generate (Presieve.singleton f)).arrows))
⊢ EffectiveEpi f

Next tactic:
rw [Sieve.generateSingleton_eq] at h
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    

Proof state:
case mp
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (IsColimit (Presieve.cocone (generateSingleton f).arrows))
⊢ EffectiveEpi f

Next tactic:
constructor
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    constructor
    

Proof state:
case mp.effectiveEpi
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (IsColimit (Presieve.cocone (generateSingleton f).arrows))
⊢ Nonempty (EffectiveEpiStruct f)

Next tactic:
apply Nonempty.map (effectiveEpiStructOfIsColimit _) h
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    constructor
    apply Nonempty.map (effectiveEpiStructOfIsColimit _) h
  · 

Proof state:
case mpr
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
⊢ EffectiveEpi f → Presieve.EffectiveEpimorphic (Presieve.singleton f)

Next tactic:
rintro ⟨h⟩
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    constructor
    apply Nonempty.map (effectiveEpiStructOfIsColimit _) h
  · rintro ⟨h⟩
    

Proof state:
case mpr.mk
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (EffectiveEpiStruct f)
⊢ Presieve.EffectiveEpimorphic (Presieve.singleton f)

Next tactic:
show Nonempty _
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    constructor
    apply Nonempty.map (effectiveEpiStructOfIsColimit _) h
  · rintro ⟨h⟩
    show Nonempty _
    

Proof state:
case mpr.mk
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (EffectiveEpiStruct f)
⊢ Nonempty (IsColimit (Presieve.cocone (generate (Presieve.singleton f)).arrows))

Next tactic:
rw [Sieve.generateSingleton_eq]
theorem Sieve.effectiveEpimorphic_singleton {X Y : C} (f : Y ⟶ X) :
    (Presieve.singleton f).EffectiveEpimorphic ↔ (EffectiveEpi f) := by
  constructor
  · intro (h : Nonempty _)
    rw [Sieve.generateSingleton_eq] at h
    constructor
    apply Nonempty.map (effectiveEpiStructOfIsColimit _) h
  · rintro ⟨h⟩
    show Nonempty _
    rw [Sieve.generateSingleton_eq]
    

Proof state:
case mpr.mk
C : Type u_1
inst✝ : Category.{u_2, u_1} C
X Y : C
f : Y ⟶ X
h : Nonempty (EffectiveEpiStruct f)
⊢ Nonempty (IsColimit (Presieve.cocone (generateSingleton f).arrows))

Next tactic:
apply Nonempty.map (isColimitOfEffectiveEpiStruct _) h
/--
The sieve of morphisms which factor through a morphism in a given family.
This is equal to `Sieve.generate (Presieve.ofArrows X π)`, but has
more convenient definitional properties.
-/
def Sieve.generateFamily {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve B where
  arrows Y := { f | ∃ (a : α) (g : Y ⟶ X a), g ≫ π a = f }
  downward_closed := by
    

Proof state:
C : Type u_1
inst✝ : Category.{?u.37664, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
⊢ ∀ {Y Z : C} {f : Y ⟶ B},
    (fun Y => {f | ∃ a g, g ≫ π a = f}) Y f → ∀ (g : Z ⟶ Y), (fun Y => {f | ∃ a g, g ≫ π a = f}) Z (g ≫ f)

Next tactic:
rintro Y₁ Y₂ g₁ ⟨a,q,rfl⟩ e
/--
The sieve of morphisms which factor through a morphism in a given family.
This is equal to `Sieve.generate (Presieve.ofArrows X π)`, but has
more convenient definitional properties.
-/
def Sieve.generateFamily {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve B where
  arrows Y := { f | ∃ (a : α) (g : Y ⟶ X a), g ≫ π a = f }
  downward_closed := by
    rintro Y₁ Y₂ g₁ ⟨a,q,rfl⟩ e
    

Proof state:
case intro.intro
C : Type u_1
inst✝ : Category.{?u.37664, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y₁ Y₂ : C
a : α
q : Y₁ ⟶ X a
e : Y₂ ⟶ Y₁
⊢ setOf (fun f => ∃ a g, g ≫ π a = f) (e ≫ q ≫ π a)

Next tactic:
exact ⟨a, e ≫ q, by simp⟩
/--
The sieve of morphisms which factor through a morphism in a given family.
This is equal to `Sieve.generate (Presieve.ofArrows X π)`, but has
more convenient definitional properties.
-/
def Sieve.generateFamily {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve B where
  arrows Y := { f | ∃ (a : α) (g : Y ⟶ X a), g ≫ π a = f }
  downward_closed := by
    rintro Y₁ Y₂ g₁ ⟨a,q,rfl⟩ e
    exact ⟨a, e ≫ q, by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.37664, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y₁ Y₂ : C
a : α
q : Y₁ ⟶ X a
e : Y₂ ⟶ Y₁
⊢ (e ≫ q) ≫ π a = e ≫ q ≫ π a

Next tactic:
simp
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  

Proof state:
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
⊢ generate (Presieve.ofArrows X π) = generateFamily X π

Next tactic:
ext Y g
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  ext Y g
  

Proof state:
case h
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y : C
g : Y ⟶ B
⊢ (generate (Presieve.ofArrows X π)).arrows g ↔ (generateFamily X π).arrows g

Next tactic:
constructor
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  ext Y g
  constructor
  · 

Proof state:
case h.mp
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y : C
g : Y ⟶ B
⊢ (generate (Presieve.ofArrows X π)).arrows g → (generateFamily X π).arrows g

Next tactic:
rintro ⟨W, g, f, ⟨a⟩, rfl⟩
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  ext Y g
  constructor
  · rintro ⟨W, g, f, ⟨a⟩, rfl⟩
    

Proof state:
case h.mp.intro.intro.intro.intro.mk
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y✝ Y : C
a : α
g : Y✝ ⟶ X a
⊢ (generateFamily X π).arrows (g ≫ π a)

Next tactic:
exact ⟨a, g, rfl⟩
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  ext Y g
  constructor
  · rintro ⟨W, g, f, ⟨a⟩, rfl⟩
    exact ⟨a, g, rfl⟩
  · 

Proof state:
case h.mpr
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y : C
g : Y ⟶ B
⊢ (generateFamily X π).arrows g → (generate (Presieve.ofArrows X π)).arrows g

Next tactic:
rintro ⟨a, g, rfl⟩
lemma Sieve.generateFamily_eq {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) :
    Sieve.generate (Presieve.ofArrows X π) = Sieve.generateFamily X π := by
  ext Y g
  constructor
  · rintro ⟨W, g, f, ⟨a⟩, rfl⟩
    exact ⟨a, g, rfl⟩
  · rintro ⟨a, g, rfl⟩
    

Proof state:
case h.mpr.intro.intro
C : Type u_1
inst✝ : Category.{u_3, u_1} C
B : C
α : Type u_2
X : α → C
π : (a : α) → X a ⟶ B
Y : C
a : α
g : Y ⟶ X a
⊢ (generate (Presieve.ofArrows X π)).arrows (g ≫ π a)

Next tactic:
exact ⟨_, g, π a, ⟨a⟩, rfl⟩
/-- The effective epi family structure on the identity -/
def effectiveEpiFamilyStructId {α : Unit → C} : EffectiveEpiFamilyStruct α (fun _ => 𝟙 (α ())) where
  desc := fun e _ => e ()
  fac := by 

Proof state:
C : Type u_1
inst✝ : Category.{?u.44295, u_1} C
α : Unit → C
⊢ ∀ {W : C} (e : (a : Unit) → α a ⟶ W)
    (h :
      ∀ {Z : C} (a₁ a₂ : Unit) (g₁ : Z ⟶ α a₁) (g₂ : Z ⟶ α a₂), g₁ ≫ 𝟙 (α ()) = g₂ ≫ 𝟙 (α ()) → g₁ ≫ e a₁ = g₂ ≫ e a₂)
    (a : Unit),
    𝟙 (α ()) ≫
        (fun {W} e x => e ()) e
          (_ :
            ∀ {Z : C} (a₁ a₂ : Unit) (g₁ : Z ⟶ α a₁) (g₂ : Z ⟶ α a₂),
              g₁ ≫ 𝟙 (α ()) = g₂ ≫ 𝟙 (α ()) → g₁ ≫ e a₁ = g₂ ≫ e a₂) =
      e a

Next tactic:
aesop_cat