l3lab/ntp-mathlib huggingface dataset:
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
⊢ f ≫ g ∈ arrows S c e ↔ f ∈ arrows S c d

Next tactic:
constructor
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  constructor
  · 

Proof state:
case mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
⊢ f ≫ g ∈ arrows S c e → f ∈ arrows S c d

Next tactic:
rintro h
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  constructor
  · rintro h
    

Proof state:
case mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
h : f ≫ g ∈ arrows S c e
⊢ f ∈ arrows S c d

Next tactic:
suffices (f ≫ g) ≫ Groupoid.inv g ∈ S.arrows c d by
      simpa only [inv_eq_inv, IsIso.hom_inv_id, Category.comp_id, Category.assoc] using this
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  constructor
  · rintro h
    suffices (f ≫ g) ≫ Groupoid.inv g ∈ S.arrows c d by
      

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
h : f ≫ g ∈ arrows S c e
this : (f ≫ g) ≫ Groupoid.inv g ∈ arrows S c d
⊢ f ∈ arrows S c d

Next tactic:
simpa only [inv_eq_inv, IsIso.hom_inv_id, Category.comp_id, Category.assoc] using this
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  constructor
  · rintro h
    suffices (f ≫ g) ≫ Groupoid.inv g ∈ S.arrows c d by
      simpa only [inv_eq_inv, IsIso.hom_inv_id, Category.comp_id, Category.assoc] using this
    · 

Proof state:
case mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
h : f ≫ g ∈ arrows S c e
⊢ (f ≫ g) ≫ Groupoid.inv g ∈ arrows S c d

Next tactic:
apply S.mul h (S.inv hg)
theorem mul_mem_cancel_right {c d e : C} {f : c ⟶ d} {g : d ⟶ e} (hg : g ∈ S.arrows d e) :
    f ≫ g ∈ S.arrows c e ↔ f ∈ S.arrows c d := by
  constructor
  · rintro h
    suffices (f ≫ g) ≫ Groupoid.inv g ∈ S.arrows c d by
      simpa only [inv_eq_inv, IsIso.hom_inv_id, Category.comp_id, Category.assoc] using this
    · apply S.mul h (S.inv hg)
  · 

Proof state:
case mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d e : C
f : c ⟶ d
g : d ⟶ e
hg : g ∈ arrows S d e
⊢ f ∈ arrows S c d → f ≫ g ∈ arrows S c e

Next tactic:
exact fun hf => S.mul hf hg
theorem id_mem_of_nonempty_isotropy (c : C) : c ∈ objs S → 𝟙 c ∈ S.arrows c c := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
⊢ c ∈ objs S → 𝟙 c ∈ arrows S c c

Next tactic:
rintro ⟨γ, hγ⟩
theorem id_mem_of_nonempty_isotropy (c : C) : c ∈ objs S → 𝟙 c ∈ S.arrows c c := by
  rintro ⟨γ, hγ⟩
  

Proof state:
case intro
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
γ : c ⟶ c
hγ : γ ∈ arrows S c c
⊢ 𝟙 c ∈ arrows S c c

Next tactic:
convert S.mul hγ (S.inv hγ)
theorem id_mem_of_nonempty_isotropy (c : C) : c ∈ objs S → 𝟙 c ∈ S.arrows c c := by
  rintro ⟨γ, hγ⟩
  convert S.mul hγ (S.inv hγ)
  

Proof state:
case h.e'_4
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
γ : c ⟶ c
hγ : γ ∈ arrows S c c
⊢ 𝟙 c = γ ≫ Groupoid.inv γ

Next tactic:
simp only [inv_eq_inv, IsIso.hom_inv_id]
@[simp]
theorem coe_inv_coe' {c d : S.objs} (p : c ⟶ d) :
    (CategoryTheory.inv p).val = CategoryTheory.inv p.val := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d : ↑(objs S)
p : c ⟶ d
⊢ ↑(inv p) = inv ↑p

Next tactic:
simp only [← inv_eq_inv, coe_inv_coe]
theorem hom.inj_on_objects : Function.Injective (hom S).obj := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ Function.Injective (hom S).toPrefunctor.obj

Next tactic:
rintro ⟨c, hc⟩ ⟨d, hd⟩ hcd
theorem hom.inj_on_objects : Function.Injective (hom S).obj := by
  rintro ⟨c, hc⟩ ⟨d, hd⟩ hcd
  

Proof state:
case mk.mk
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
hc : c ∈ objs S
d : C
hd : d ∈ objs S
hcd : (hom S).obj { val := c, property := hc } = (hom S).obj { val := d, property := hd }
⊢ { val := c, property := hc } = { val := d, property := hd }

Next tactic:
simp only [Subtype.mk_eq_mk]
theorem hom.inj_on_objects : Function.Injective (hom S).obj := by
  rintro ⟨c, hc⟩ ⟨d, hd⟩ hcd
  simp only [Subtype.mk_eq_mk]; 

Proof state:
case mk.mk
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
hc : c ∈ objs S
d : C
hd : d ∈ objs S
hcd : (hom S).obj { val := c, property := hc } = (hom S).obj { val := d, property := hd }
⊢ c = d

Next tactic:
exact hcd
theorem hom.faithful : ∀ c d, Function.Injective fun f : c ⟶ d => (hom S).map f := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ (c d : ↑(objs S)), Function.Injective fun f => (hom S).map f

Next tactic:
rintro ⟨c, hc⟩ ⟨d, hd⟩ ⟨f, hf⟩ ⟨g, hg⟩ hfg
theorem hom.faithful : ∀ c d, Function.Injective fun f : c ⟶ d => (hom S).map f := by
  rintro ⟨c, hc⟩ ⟨d, hd⟩ ⟨f, hf⟩ ⟨g, hg⟩ hfg; 

Proof state:
case mk.mk.mk.mk
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
hc : c ∈ objs S
d : C
hd : d ∈ objs S
f : ↑{ val := c, property := hc } ⟶ ↑{ val := d, property := hd }
hf : f ∈ arrows S ↑{ val := c, property := hc } ↑{ val := d, property := hd }
g : ↑{ val := c, property := hc } ⟶ ↑{ val := d, property := hd }
hg : g ∈ arrows S ↑{ val := c, property := hc } ↑{ val := d, property := hd }
hfg : (fun f => (hom S).map f) { val := f, property := hf } = (fun f => (hom S).map f) { val := g, property := hg }
⊢ { val := f, property := hf } = { val := g, property := hg }

Next tactic:
exact Subtype.eq hfg
instance : SetLike (Subgroupoid C) (Σ c d : C, c ⟶ d) where
  coe := toSet
  coe_injective' := fun ⟨S, _, _⟩ ⟨T, _, _⟩ h => by 

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ x✝¹ x✝ : Subgroupoid C
S : (c d : C) → Set (c ⟶ d)
inv✝¹ : ∀ {c d : C} {p : c ⟶ d}, p ∈ S c d → Groupoid.inv p ∈ S d c
mul✝¹ : ∀ {c d e : C} {p : c ⟶ d}, p ∈ S c d → ∀ {q : d ⟶ e}, q ∈ S d e → p ≫ q ∈ S c e
T : (c d : C) → Set (c ⟶ d)
inv✝ : ∀ {c d : C} {p : c ⟶ d}, p ∈ T c d → Groupoid.inv p ∈ T d c
mul✝ : ∀ {c d e : C} {p : c ⟶ d}, p ∈ T c d → ∀ {q : d ⟶ e}, q ∈ T d e → p ≫ q ∈ T c e
h : ↑{ arrows := S, inv := inv✝¹, mul := mul✝¹ } = ↑{ arrows := T, inv := inv✝, mul := mul✝ }
⊢ { arrows := S, inv := inv✝¹, mul := mul✝¹ } = { arrows := T, inv := inv✝, mul := mul✝ }

Next tactic:
ext c d f
instance : SetLike (Subgroupoid C) (Σ c d : C, c ⟶ d) where
  coe := toSet
  coe_injective' := fun ⟨S, _, _⟩ ⟨T, _, _⟩ h => by ext c d f; 

Proof state:
case arrows.h.h.h
C : Type u
inst✝ : Groupoid C
S✝ x✝¹ x✝ : Subgroupoid C
S : (c d : C) → Set (c ⟶ d)
inv✝¹ : ∀ {c d : C} {p : c ⟶ d}, p ∈ S c d → Groupoid.inv p ∈ S d c
mul✝¹ : ∀ {c d e : C} {p : c ⟶ d}, p ∈ S c d → ∀ {q : d ⟶ e}, q ∈ S d e → p ≫ q ∈ S c e
T : (c d : C) → Set (c ⟶ d)
inv✝ : ∀ {c d : C} {p : c ⟶ d}, p ∈ T c d → Groupoid.inv p ∈ T d c
mul✝ : ∀ {c d e : C} {p : c ⟶ d}, p ∈ T c d → ∀ {q : d ⟶ e}, q ∈ T d e → p ≫ q ∈ T c e
h : ↑{ arrows := S, inv := inv✝¹, mul := mul✝¹ } = ↑{ arrows := T, inv := inv✝, mul := mul✝ }
c d : C
f : c ⟶ d
⊢ f ∈ arrows { arrows := S, inv := inv✝¹, mul := mul✝¹ } c d ↔ f ∈ arrows { arrows := T, inv := inv✝, mul := mul✝ } c d

Next tactic:
apply Set.ext_iff.1 h ⟨c, d, f⟩
theorem le_iff (S T : Subgroupoid C) : S ≤ T ↔ ∀ {c d}, S.arrows c d ⊆ T.arrows c d := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
⊢ S ≤ T ↔ ∀ {c d : C}, arrows S c d ⊆ arrows T c d

Next tactic:
rw [SetLike.le_def, Sigma.forall]
theorem le_iff (S T : Subgroupoid C) : S ≤ T ↔ ∀ {c d}, S.arrows c d ⊆ T.arrows c d := by
  rw [SetLike.le_def, Sigma.forall]; 

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
⊢ (∀ (a : C) (b : (d : C) × (a ⟶ d)), { fst := a, snd := b } ∈ S → { fst := a, snd := b } ∈ T) ↔
    ∀ {c d : C}, arrows S c d ⊆ arrows T c d

Next tactic:
exact forall_congr' fun c => Sigma.forall
instance : Top (Subgroupoid C) :=
  ⟨{  arrows := fun _ _ => Set.univ
      mul := by intros; trivial
      inv := by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ {c d : C} {p : c ⟶ d}, p ∈ (fun x x_1 => univ) c d → Groupoid.inv p ∈ (fun x x_1 => univ) d c

Next tactic:
intros
instance : Top (Subgroupoid C) :=
  ⟨{  arrows := fun _ _ => Set.univ
      mul := by intros; trivial
      inv := by intros; 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d✝ : C
p✝ : c✝ ⟶ d✝
a✝ : p✝ ∈ (fun x x_1 => univ) c✝ d✝
⊢ Groupoid.inv p✝ ∈ (fun x x_1 => univ) d✝ c✝

Next tactic:
trivial
instance : Top (Subgroupoid C) :=
  ⟨{  arrows := fun _ _ => Set.univ
      mul := by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ {c d e : C} {p : c ⟶ d},
    p ∈ (fun x x_1 => univ) c d → ∀ {q : d ⟶ e}, q ∈ (fun x x_1 => univ) d e → p ≫ q ∈ (fun x x_1 => univ) c e

Next tactic:
intros
instance : Top (Subgroupoid C) :=
  ⟨{  arrows := fun _ _ => Set.univ
      mul := by intros; 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d✝ e✝ : C
p✝ : c✝ ⟶ d✝
a✝¹ : p✝ ∈ (fun x x_1 => univ) c✝ d✝
q✝ : d✝ ⟶ e✝
a✝ : q✝ ∈ (fun x x_1 => univ) d✝ e✝
⊢ p✝ ≫ q✝ ∈ (fun x x_1 => univ) c✝ e✝

Next tactic:
trivial
theorem mem_top_objs (c : C) : c ∈ (⊤ : Subgroupoid C).objs := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
⊢ c ∈ objs ⊤

Next tactic:
dsimp [Top.top, objs]
theorem mem_top_objs (c : C) : c ∈ (⊤ : Subgroupoid C).objs := by
  dsimp [Top.top, objs]
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
⊢ Set.Nonempty univ

Next tactic:
simp only [univ_nonempty]
instance : InfSet (Subgroupoid C) :=
  ⟨fun s =>
    { arrows := fun c d => ⋂ S ∈ s, Subgroupoid.arrows S c d
      inv := fun hp ↦ by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
c✝ d✝ : C
p✝ : c✝ ⟶ d✝
hp : p✝ ∈ (fun c d => ⋂ S ∈ s, arrows S c d) c✝ d✝
⊢ Groupoid.inv p✝ ∈ (fun c d => ⋂ S ∈ s, arrows S c d) d✝ c✝

Next tactic:
rw [mem_iInter₂] at hp ⊢
instance : InfSet (Subgroupoid C) :=
  ⟨fun s =>
    { arrows := fun c d => ⋂ S ∈ s, Subgroupoid.arrows S c d
      inv := fun hp ↦ by rw [mem_iInter₂] at hp ⊢; 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
c✝ d✝ : C
p✝ : c✝ ⟶ d✝
hp : ∀ i ∈ s, p✝ ∈ arrows i c✝ d✝
⊢ ∀ i ∈ s, Groupoid.inv p✝ ∈ arrows i d✝ c✝

Next tactic:
exact fun S hS => S.inv (hp S hS)
instance : InfSet (Subgroupoid C) :=
  ⟨fun s =>
    { arrows := fun c d => ⋂ S ∈ s, Subgroupoid.arrows S c d
      inv := fun hp ↦ by rw [mem_iInter₂] at hp ⊢; exact fun S hS => S.inv (hp S hS)
      mul := fun hp _ hq ↦ by
        

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
c✝ d✝ e✝ : C
p✝ : c✝ ⟶ d✝
hp : p✝ ∈ (fun c d => ⋂ S ∈ s, arrows S c d) c✝ d✝
x✝ : d✝ ⟶ e✝
hq : x✝ ∈ (fun c d => ⋂ S ∈ s, arrows S c d) d✝ e✝
⊢ p✝ ≫ x✝ ∈ (fun c d => ⋂ S ∈ s, arrows S c d) c✝ e✝

Next tactic:
rw [mem_iInter₂] at hp hq ⊢
instance : InfSet (Subgroupoid C) :=
  ⟨fun s =>
    { arrows := fun c d => ⋂ S ∈ s, Subgroupoid.arrows S c d
      inv := fun hp ↦ by rw [mem_iInter₂] at hp ⊢; exact fun S hS => S.inv (hp S hS)
      mul := fun hp _ hq ↦ by
        rw [mem_iInter₂] at hp hq ⊢;
        

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
c✝ d✝ e✝ : C
p✝ : c✝ ⟶ d✝
hp : ∀ i ∈ s, p✝ ∈ arrows i c✝ d✝
x✝ : d✝ ⟶ e✝
hq : ∀ i ∈ s, x✝ ∈ arrows i d✝ e✝
⊢ ∀ i ∈ s, p✝ ≫ x✝ ∈ arrows i c✝ e✝

Next tactic:
exact fun S hS => S.mul (hp S hS) (hq S hS)
instance : CompleteLattice (Subgroupoid C) :=
  { completeLatticeOfInf (Subgroupoid C) (by
      

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ (s : Set (Subgroupoid C)), IsGLB s (sInf s)

Next tactic:
refine' fun s => ⟨fun S Ss F => _, fun T Tl F fT => _⟩
instance : CompleteLattice (Subgroupoid C) :=
  { completeLatticeOfInf (Subgroupoid C) (by
      refine' fun s => ⟨fun S Ss F => _, fun T Tl F fT => _⟩ <;> 

Proof state:
case refine'_1
C : Type u
inst✝ : Groupoid C
S✝ : Subgroupoid C
s : Set (Subgroupoid C)
S : Subgroupoid C
Ss : S ∈ s
F : (c : C) × (d : C) × (c ⟶ d)
⊢ F ∈ sInf s → F ∈ S

Next tactic:
simp only [mem_sInf]
instance : CompleteLattice (Subgroupoid C) :=
  { completeLatticeOfInf (Subgroupoid C) (by
      refine' fun s => ⟨fun S Ss F => _, fun T Tl F fT => _⟩ <;> 

Proof state:
case refine'_2
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
T : Subgroupoid C
Tl : T ∈ lowerBounds s
F : (c : C) × (d : C) × (c ⟶ d)
fT : F ∈ T
⊢ F ∈ sInf s

Next tactic:
simp only [mem_sInf]
instance : CompleteLattice (Subgroupoid C) :=
  { completeLatticeOfInf (Subgroupoid C) (by
      refine' fun s => ⟨fun S Ss F => _, fun T Tl F fT => _⟩ <;> simp only [mem_sInf]
      

Proof state:
case refine'_1
C : Type u
inst✝ : Groupoid C
S✝ : Subgroupoid C
s : Set (Subgroupoid C)
S : Subgroupoid C
Ss : S ∈ s
F : (c : C) × (d : C) × (c ⟶ d)
⊢ (∀ S ∈ s, F ∈ S) → F ∈ S
case refine'_2
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
s : Set (Subgroupoid C)
T : Subgroupoid C
Tl : T ∈ lowerBounds s
F : (c : C) × (d : C) × (c ⟶ d)
fT : F ∈ T
⊢ ∀ S ∈ s, F ∈ S

Next tactic:
exacts [fun hp => hp S Ss, fun S Ss => Tl Ss fT]
theorem inclusion_inj_on_objects {S T : Subgroupoid C} (h : S ≤ T) :
    Function.Injective (inclusion h).obj := fun ⟨s, hs⟩ ⟨t, ht⟩ => by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
h : S ≤ T
x✝¹ x✝ : ↑(objs S)
s : C
hs : s ∈ objs S
t : C
ht : t ∈ objs S
⊢ (inclusion h).obj { val := s, property := hs } = (inclusion h).obj { val := t, property := ht } →
    { val := s, property := hs } = { val := t, property := ht }

Next tactic:
simpa only [inclusion, Subtype.mk_eq_mk] using id
theorem inclusion_faithful {S T : Subgroupoid C} (h : S ≤ T) (s t : S.objs) :
    Function.Injective fun f : s ⟶ t => (inclusion h).map f := fun ⟨f, hf⟩ ⟨g, hg⟩ => by
  -- porting note: was `...; simpa only [Subtype.mk_eq_mk] using id`
  

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
h : S ≤ T
s t : ↑(objs S)
x✝¹ x✝ : s ⟶ t
f : ↑s ⟶ ↑t
hf : f ∈ arrows S ↑s ↑t
g : ↑s ⟶ ↑t
hg : g ∈ arrows S ↑s ↑t
⊢ (fun f => (inclusion h).map f) { val := f, property := hf } =
      (fun f => (inclusion h).map f) { val := g, property := hg } →
    { val := f, property := hf } = { val := g, property := hg }

Next tactic:
dsimp only [inclusion]
theorem inclusion_faithful {S T : Subgroupoid C} (h : S ≤ T) (s t : S.objs) :
    Function.Injective fun f : s ⟶ t => (inclusion h).map f := fun ⟨f, hf⟩ ⟨g, hg⟩ => by
  -- porting note: was `...; simpa only [Subtype.mk_eq_mk] using id`
  dsimp only [inclusion]; 

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
h : S ≤ T
s t : ↑(objs S)
x✝¹ x✝ : s ⟶ t
f : ↑s ⟶ ↑t
hf : f ∈ arrows S ↑s ↑t
g : ↑s ⟶ ↑t
hg : g ∈ arrows S ↑s ↑t
⊢ { val := f, property := (_ : { fst := ↑s, snd := { fst := ↑t, snd := ↑{ val := f, property := hf } } } ∈ T) } =
      { val := g, property := (_ : { fst := ↑s, snd := { fst := ↑t, snd := ↑{ val := g, property := hg } } } ∈ T) } →
    { val := f, property := hf } = { val := g, property := hg }

Next tactic:
rw [Subtype.mk_eq_mk, Subtype.mk_eq_mk]
theorem inclusion_faithful {S T : Subgroupoid C} (h : S ≤ T) (s t : S.objs) :
    Function.Injective fun f : s ⟶ t => (inclusion h).map f := fun ⟨f, hf⟩ ⟨g, hg⟩ => by
  -- porting note: was `...; simpa only [Subtype.mk_eq_mk] using id`
  dsimp only [inclusion]; rw [Subtype.mk_eq_mk, Subtype.mk_eq_mk]; 

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S T : Subgroupoid C
h : S ≤ T
s t : ↑(objs S)
x✝¹ x✝ : s ⟶ t
f : ↑s ⟶ ↑t
hf : f ∈ arrows S ↑s ↑t
g : ↑s ⟶ ↑t
hg : g ∈ arrows S ↑s ↑t
⊢ f = g → f = g

Next tactic:
exact id
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ {c d : C} {p : c ⟶ d},
    p ∈ (fun c d => {p | Discrete.Arrows c d p}) c d → Groupoid.inv p ∈ (fun c d => {p | Discrete.Arrows c d p}) d c

Next tactic:
rintro _ _ _ ⟨⟩
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by rintro _ _ _ ⟨⟩; 

Proof state:
case id
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d : C
⊢ Groupoid.inv (𝟙 c✝) ∈ (fun c d => {p | Discrete.Arrows c d p}) c✝ c✝

Next tactic:
simp only [inv_eq_inv, IsIso.inv_id]
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by rintro _ _ _ ⟨⟩; simp only [inv_eq_inv, IsIso.inv_id]; 

Proof state:
case id
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d : C
⊢ 𝟙 c✝ ∈ {p | Discrete.Arrows c✝ c✝ p}

Next tactic:
constructor
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by rintro _ _ _ ⟨⟩; simp only [inv_eq_inv, IsIso.inv_id]; constructor
  mul := by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ ∀ {c d e : C} {p : c ⟶ d},
    p ∈ (fun c d => {p | Discrete.Arrows c d p}) c d →
      ∀ {q : d ⟶ e},
        q ∈ (fun c d => {p | Discrete.Arrows c d p}) d e → p ≫ q ∈ (fun c d => {p | Discrete.Arrows c d p}) c e

Next tactic:
rintro _ _ _ _ ⟨⟩ _ ⟨⟩
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by rintro _ _ _ ⟨⟩; simp only [inv_eq_inv, IsIso.inv_id]; constructor
  mul := by rintro _ _ _ _ ⟨⟩ _ ⟨⟩; 

Proof state:
case id.id
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d✝ d : C
⊢ 𝟙 c✝ ≫ 𝟙 c✝ ∈ (fun c d => {p | Discrete.Arrows c d p}) c✝ c✝

Next tactic:
rw [Category.comp_id]
/-- The only arrows of the discrete groupoid are the identity arrows. -/
def discrete : Subgroupoid C where
  arrows c d := {p | Discrete.Arrows c d p}
  inv := by rintro _ _ _ ⟨⟩; simp only [inv_eq_inv, IsIso.inv_id]; constructor
  mul := by rintro _ _ _ _ ⟨⟩ _ ⟨⟩; rw [Category.comp_id]; 

Proof state:
case id.id
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c✝ d✝ d : C
⊢ 𝟙 c✝ ∈ (fun c d => {p | Discrete.Arrows c d p}) c✝ c✝

Next tactic:
constructor
theorem mem_discrete_iff {c d : C} (f : c ⟶ d) :
    f ∈ discrete.arrows c d ↔ ∃ h : c = d, f = eqToHom h :=
  ⟨by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d : C
f : c ⟶ d
⊢ f ∈ arrows discrete c d → ∃ (h : c = d), f = eqToHom h

Next tactic:
rintro ⟨⟩
theorem mem_discrete_iff {c d : C} (f : c ⟶ d) :
    f ∈ discrete.arrows c d ↔ ∃ h : c = d, f = eqToHom h :=
  ⟨by rintro ⟨⟩; 

Proof state:
case id
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d : C
⊢ ∃ (h : c = c), 𝟙 c = eqToHom h

Next tactic:
exact ⟨rfl, rfl⟩
theorem mem_discrete_iff {c d : C} (f : c ⟶ d) :
    f ∈ discrete.arrows c d ↔ ∃ h : c = d, f = eqToHom h :=
  ⟨by rintro ⟨⟩; exact ⟨rfl, rfl⟩, by 

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c d : C
f : c ⟶ d
⊢ (∃ (h : c = d), f = eqToHom h) → f ∈ arrows discrete c d

Next tactic:
rintro ⟨rfl, rfl⟩
theorem mem_discrete_iff {c d : C} (f : c ⟶ d) :
    f ∈ discrete.arrows c d ↔ ∃ h : c = d, f = eqToHom h :=
  ⟨by rintro ⟨⟩; exact ⟨rfl, rfl⟩, by rintro ⟨rfl, rfl⟩; 

Proof state:
case intro
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
c : C
⊢ eqToHom (_ : c = c) ∈ arrows discrete c c

Next tactic:
constructor
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  

Proof state:
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ IsWide S ↔ objs S = univ

Next tactic:
constructor
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · 

Proof state:
case mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ IsWide S → objs S = univ

Next tactic:
rintro h
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    

Proof state:
case mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : IsWide S
⊢ objs S = univ

Next tactic:
ext x
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; 

Proof state:
case mp.h
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : IsWide S
x : C
⊢ x ∈ objs S ↔ x ∈ univ

Next tactic:
constructor
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> 

Proof state:
case mp.h.mp
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : IsWide S
x : C
⊢ x ∈ objs S → x ∈ univ

Next tactic:
simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> 

Proof state:
case mp.h.mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : IsWide S
x : C
⊢ x ∈ univ → x ∈ objs S

Next tactic:
simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
    

Proof state:
case mp.h.mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : IsWide S
x : C
⊢ x ∈ objs S

Next tactic:
apply mem_objs_of_src S (h.wide x)
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
    apply mem_objs_of_src S (h.wide x)
  · 

Proof state:
case mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
⊢ objs S = univ → IsWide S

Next tactic:
rintro h
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
    apply mem_objs_of_src S (h.wide x)
  · rintro h
    

Proof state:
case mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : objs S = univ
⊢ IsWide S

Next tactic:
refine' ⟨fun c => _⟩
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
    apply mem_objs_of_src S (h.wide x)
  · rintro h
    refine' ⟨fun c => _⟩
    

Proof state:
case mpr
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : objs S = univ
c : C
⊢ 𝟙 c ∈ arrows S c c

Next tactic:
obtain ⟨γ, γS⟩ := (le_of_eq h.symm : ⊤ ⊆ S.objs) (Set.mem_univ c)
theorem isWide_iff_objs_eq_univ : S.IsWide ↔ S.objs = Set.univ := by
  constructor
  · rintro h
    ext x; constructor <;> simp only [top_eq_univ, mem_univ, imp_true_iff, forall_true_left]
    apply mem_objs_of_src S (h.wide x)
  · rintro h
    refine' ⟨fun c => _⟩
    obtain ⟨γ, γS⟩ := (le_of_eq h.symm : ⊤ ⊆ S.objs) (Set.mem_univ c)
    

Proof state:
case mpr.intro
C : Type u
inst✝ : Groupoid C
S : Subgroupoid C
h : objs S = univ
c : C
γ : c ⟶ c
γS : γ ∈ arrows S c c
⊢ 𝟙 c ∈ arrows S c c

Next tactic:
exact id_mem_of_src S γS
theorem IsWide.eqToHom_mem {S : Subgroupoid C} (Sw : S.IsWide) {c d : C} (h : c = d) :
    eqToHom h ∈ S.arrows c d := by 

Proof state:
C : Type u
inst✝ : Groupoid C
S✝ S : Subgroupoid C
Sw : IsWide S
c d : C
h : c = d
⊢ eqToHom h ∈ arrows S c d

Next tactic:
cases h
theorem IsWide.eqToHom_mem {S : Subgroupoid C} (Sw : S.IsWide) {c d : C} (h : c = d) :
    eqToHom h ∈ S.arrows c d := by cases h; 

Proof state:
case refl
C : Type u
inst✝ : Groupoid C
S✝ S : Subgroupoid C
Sw : IsWide S
c : C
⊢ eqToHom (_ : c = c) ∈ arrows S c c

Next tactic:
simp only [eqToHom_refl]
theorem IsWide.eqToHom_mem {S : Subgroupoid C} (Sw : S.IsWide) {c d : C} (h : c = d) :
    eqToHom h ∈ S.arrows c d := by cases h; simp only [eqToHom_refl]; 

Proof state:
case refl
C : Type u
inst✝ : Groupoid C
S✝ S : Subgroupoid C
Sw : IsWide S
c : C
⊢ 𝟙 c ∈ arrows S c c

Next tactic:
apply Sw.id_mem c