l3lab/ntp-mathlib huggingface dataset:
/-- If `f : β → α` sends any two distinct points to points at distance at least `ε > 0`, then
`f` is a uniform embedding with respect to the discrete uniformity on `β`. -/
theorem uniformEmbedding_bot_of_pairwise_le_dist {β : Type*} {ε : ℝ} (hε : 0 < ε) {f : β → α}
    (hf : Pairwise fun x y => ε ≤ dist (f x) (f y)) :
    @UniformEmbedding _ _ ⊥ (by infer_instance) f :=
  uniformEmbedding_of_spaced_out (dist_mem_uniformity hε) <| by 

Proof state:
α : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ : Type w
inst✝ : MetricSpace γ
x : γ
s : Set γ
β : Type u_3
ε : ℝ
hε : 0 < ε
f : β → α
hf : Pairwise fun x y => ε ≤ dist (f x) (f y)
⊢ Pairwise fun x y => (f x, f y) ∉ {p | dist p.1 p.2 < ε}

Next tactic:
simpa using hf
theorem MetricSpace.replaceUniformity_eq {γ} [U : UniformSpace γ] (m : MetricSpace γ)
    (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : m.replaceUniformity H = m := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ✝ : Type w
inst✝ : MetricSpace γ✝
γ : Type u_3
U : UniformSpace γ
m : MetricSpace γ
H : 𝓤 γ = 𝓤 γ
⊢ replaceUniformity m H = m

Next tactic:
ext
theorem MetricSpace.replaceUniformity_eq {γ} [U : UniformSpace γ] (m : MetricSpace γ)
    (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : m.replaceUniformity H = m := by
  ext; 

Proof state:
case h.dist.h.h
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ✝ : Type w
inst✝ : MetricSpace γ✝
γ : Type u_3
U : UniformSpace γ
m : MetricSpace γ
H : 𝓤 γ = 𝓤 γ
x✝¹ x✝ : γ
⊢ dist x✝¹ x✝ = dist x✝¹ x✝

Next tactic:
rfl
theorem MetricSpace.replaceTopology_eq {γ} [U : TopologicalSpace γ] (m : MetricSpace γ)
    (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) :
    m.replaceTopology H = m := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ✝ : Type w
inst✝ : MetricSpace γ✝
γ : Type u_3
U : TopologicalSpace γ
m : MetricSpace γ
H : U = UniformSpace.toTopologicalSpace
⊢ replaceTopology m H = m

Next tactic:
ext
theorem MetricSpace.replaceTopology_eq {γ} [U : TopologicalSpace γ] (m : MetricSpace γ)
    (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) :
    m.replaceTopology H = m := by
  ext; 

Proof state:
case h.dist.h.h
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ✝ : Type w
inst✝ : MetricSpace γ✝
γ : Type u_3
U : TopologicalSpace γ
m : MetricSpace γ
H : U = UniformSpace.toTopologicalSpace
x✝¹ x✝ : γ
⊢ dist x✝¹ x✝ = dist x✝¹ x✝

Next tactic:
rfl
theorem MetricSpace.replaceBornology_eq {α} [m : MetricSpace α] [B : Bornology α]
    (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) :
    MetricSpace.replaceBornology _ H = m := by
  

Proof state:
α✝ : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α✝
γ : Type w
inst✝ : MetricSpace γ
α : Type u_3
m : MetricSpace α
B : Bornology α
H : ∀ (s : Set α), IsBounded s ↔ IsBounded s
⊢ replaceBornology m H = m

Next tactic:
ext
theorem MetricSpace.replaceBornology_eq {α} [m : MetricSpace α] [B : Bornology α]
    (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) :
    MetricSpace.replaceBornology _ H = m := by
  ext
  

Proof state:
case h.dist.h.h
α✝ : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α✝
γ : Type w
inst✝ : MetricSpace γ
α : Type u_3
m : MetricSpace α
B : Bornology α
H : ∀ (s : Set α), IsBounded s ↔ IsBounded s
x✝¹ x✝ : α
⊢ dist x✝¹ x✝ = dist x✝¹ x✝

Next tactic:
rfl
instance : MetricSpace Empty where
  dist _ _ := 0
  dist_self _ := rfl
  dist_comm _ _ := rfl
  edist _ _ := 0
  edist_dist _ _ := ENNReal.ofReal_zero.symm -- porting note: should not be needed
  eq_of_dist_eq_zero _ := Subsingleton.elim _ _
  dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by 

Proof state:
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ : Type w
inst✝ : MetricSpace γ
x✝² x✝¹ x✝ : Empty
⊢ 0 ≤ 0 + 0

Next tactic:
rw [add_zero]
instance : MetricSpace PUnit.{u + 1} where
  dist _ _ := 0
  dist_self _ := rfl
  dist_comm _ _ := rfl
  edist _ _ := 0
  edist_dist _ _ := ENNReal.ofReal_zero.symm -- porting note: should not be needed
  eq_of_dist_eq_zero _ := Subsingleton.elim _ _
  dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by 

Proof state:
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ : Type w
inst✝ : MetricSpace γ
x✝² x✝¹ x✝ : PUnit.{u + 1}
⊢ 0 ≤ 0 + 0

Next tactic:
rw [add_zero]
instance : MetricSpace PUnit.{u + 1} where
  dist _ _ := 0
  dist_self _ := rfl
  dist_comm _ _ := rfl
  edist _ _ := 0
  edist_dist _ _ := ENNReal.ofReal_zero.symm -- porting note: should not be needed
  eq_of_dist_eq_zero _ := Subsingleton.elim _ _
  dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by rw [add_zero]
  toUniformSpace := inferInstance
  uniformity_dist := by
    

Proof state:
α : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝¹ : PseudoMetricSpace α
γ : Type w
inst✝ : MetricSpace γ
⊢ 𝓤 PUnit.{u + 1} = ⨅ ε, ⨅ (_ : ε > 0), 𝓟 {p | dist p.1 p.2 < ε}

Next tactic:
simp (config := { contextual := true }) [principal_univ, eq_top_of_neBot (𝓤 PUnit)]
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  

Proof state:
α✝ : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
⊢ SecondCountableTopology α

Next tactic:
refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  

Proof state:
α✝ : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
⊢ ∃ s, Set.Countable s ∧ ∀ (x : α), ∃ y ∈ s, dist x y ≤ ε

Next tactic:
rcases H ε ε0 with ⟨β, fβ, F, hF⟩
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  rcases H ε ε0 with ⟨β, fβ, F, hF⟩
  

Proof state:
case intro.intro.intro
α✝ : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
β : Type u_3
fβ : Encodable β
F : α → β
hF : ∀ (x y : α), F x = F y → dist x y ≤ ε
⊢ ∃ s, Set.Countable s ∧ ∀ (x : α), ∃ y ∈ s, dist x y ≤ ε

Next tactic:
let Finv := rangeSplitting F
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  rcases H ε ε0 with ⟨β, fβ, F, hF⟩
  let Finv := rangeSplitting F
  

Proof state:
case intro.intro.intro
α✝ : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
β : Type u_3
fβ : Encodable β
F : α → β
hF : ∀ (x y : α), F x = F y → dist x y ≤ ε
Finv : ↑(range F) → α := rangeSplitting F
⊢ ∃ s, Set.Countable s ∧ ∀ (x : α), ∃ y ∈ s, dist x y ≤ ε

Next tactic:
refine ⟨range Finv, ⟨countable_range _, fun x => ?_⟩⟩
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  rcases H ε ε0 with ⟨β, fβ, F, hF⟩
  let Finv := rangeSplitting F
  refine ⟨range Finv, ⟨countable_range _, fun x => ?_⟩⟩
  

Proof state:
case intro.intro.intro
α✝ : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
β : Type u_3
fβ : Encodable β
F : α → β
hF : ∀ (x y : α), F x = F y → dist x y ≤ ε
Finv : ↑(range F) → α := rangeSplitting F
x : α
⊢ ∃ y ∈ range Finv, dist x y ≤ ε

Next tactic:
let x' := Finv ⟨F x, mem_range_self _⟩
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  rcases H ε ε0 with ⟨β, fβ, F, hF⟩
  let Finv := rangeSplitting F
  refine ⟨range Finv, ⟨countable_range _, fun x => ?_⟩⟩
  let x' := Finv ⟨F x, mem_range_self _⟩
  

Proof state:
case intro.intro.intro
α✝ : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
β : Type u_3
fβ : Encodable β
F : α → β
hF : ∀ (x y : α), F x = F y → dist x y ≤ ε
Finv : ↑(range F) → α := rangeSplitting F
x : α
x' : α := Finv { val := F x, property := (_ : F x ∈ range F) }
⊢ ∃ y ∈ range Finv, dist x y ≤ ε

Next tactic:
have : F x' = F x := apply_rangeSplitting F _
/-- A metric space is second countable if one can reconstruct up to any `ε>0` any element of the
space from countably many data. -/
theorem secondCountable_of_countable_discretization {α : Type u} [MetricSpace α]
    (H : ∀ ε > (0 : ℝ), ∃ (β : Type*) (_ : Encodable β) (F : α → β),
      ∀ x y, F x = F y → dist x y ≤ ε) :
    SecondCountableTopology α := by
  refine secondCountable_of_almost_dense_set fun ε ε0 => ?_
  rcases H ε ε0 with ⟨β, fβ, F, hF⟩
  let Finv := rangeSplitting F
  refine ⟨range Finv, ⟨countable_range _, fun x => ?_⟩⟩
  let x' := Finv ⟨F x, mem_range_self _⟩
  have : F x' = F x := apply_rangeSplitting F _
  

Proof state:
case intro.intro.intro
α✝ : Type u
β✝ : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : MetricSpace α
H : ∀ ε > 0, ∃ β x F, ∀ (x y : α), F x = F y → dist x y ≤ ε
ε : ℝ
ε0 : ε > 0
β : Type u_3
fβ : Encodable β
F : α → β
hF : ∀ (x y : α), F x = F y → dist x y ≤ ε
Finv : ↑(range F) → α := rangeSplitting F
x : α
x' : α := Finv { val := F x, property := (_ : F x ∈ range F) }
this : F x' = F x
⊢ ∃ y ∈ range Finv, dist x y ≤ ε

Next tactic:
exact ⟨x', mem_range_self _, hF _ _ this.symm⟩
instance {α : Type u} [PseudoMetricSpace α] : Dist (UniformSpace.SeparationQuotient α) where
  dist p q := Quotient.liftOn₂' p q dist <| fun x y x' y' hx hy => by
    

Proof state:
α✝ : Type u
β : Type v
X : Type u_1
ι : Type u_2
inst✝² : PseudoMetricSpace α✝
γ : Type w
inst✝¹ : MetricSpace γ
α : Type u
inst✝ : PseudoMetricSpace α
p q : UniformSpace.SeparationQuotient α
x y x' y' : α
hx : Setoid.r x x'
hy : Setoid.r y y'
⊢ dist x y = dist x' y'

Next tactic:
rw [dist_edist, dist_edist, ← UniformSpace.SeparationQuotient.edist_mk x,
      ← UniformSpace.SeparationQuotient.edist_mk x', Quot.sound hx, Quot.sound hy]
@[to_additive]
theorem ker_eq_bot_of_cancel {f : A →* B} (h : ∀ u v : f.ker →* A, f.comp u = f.comp v → u = v) :
    f.ker = ⊥ := by 

Proof state:
A : Type u
B : Type v
inst✝¹ : Group A
inst✝ : Group B
f : A →* B
h : ∀ (u v : ↥(ker f) →* A), comp f u = comp f v → u = v
⊢ ker f = ⊥

Next tactic:
simpa using _root_.congr_arg range (h f.ker.subtype 1 (by aesop_cat))
@[to_additive]
theorem ker_eq_bot_of_cancel {f : A →* B} (h : ∀ u v : f.ker →* A, f.comp u = f.comp v → u = v) :
    f.ker = ⊥ := by simpa using _root_.congr_arg range (h f.ker.subtype 1 (by 

Proof state:
A : Type u
B : Type v
inst✝¹ : Group A
inst✝ : Group B
f : A →* B
h : ∀ (u v : ↥(ker f) →* A), comp f u = comp f v → u = v
⊢ comp f (Subgroup.subtype (ker f)) = comp f 1

Next tactic:
aesop_cat
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  

Proof state:
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ∀ (u v : B →* B ⧸ range f), comp u f = comp v f → u = v
⊢ range f = ⊤

Next tactic:
specialize h 1 (QuotientGroup.mk' _) _
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · 

Proof state:
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ∀ (u v : B →* B ⧸ range f), comp u f = comp v f → u = v
⊢ comp 1 f = comp (QuotientGroup.mk' (range f)) f

Next tactic:
ext1 x
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    

Proof state:
case h
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ∀ (u v : B →* B ⧸ range f), comp u f = comp v f → u = v
x : A
⊢ (comp 1 f) x = (comp (QuotientGroup.mk' (range f)) f) x

Next tactic:
simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
    

Proof state:
case h
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ∀ (u v : B →* B ⧸ range f), comp u f = comp v f → u = v
x : A
⊢ 1 = ↑(f x)

Next tactic:
rw [show (1 : B ⧸ f.range) = (1 : B) from QuotientGroup.mk_one _, QuotientGroup.eq, inv_one,
      one_mul]
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
    rw [show (1 : B ⧸ f.range) = (1 : B) from QuotientGroup.mk_one _, QuotientGroup.eq, inv_one,
      one_mul]
    

Proof state:
case h
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ∀ (u v : B →* B ⧸ range f), comp u f = comp v f → u = v
x : A
⊢ f x ∈ range f

Next tactic:
exact ⟨x, rfl⟩
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
    rw [show (1 : B ⧸ f.range) = (1 : B) from QuotientGroup.mk_one _, QuotientGroup.eq, inv_one,
      one_mul]
    exact ⟨x, rfl⟩
  

Proof state:
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : 1 = QuotientGroup.mk' (range f)
⊢ range f = ⊤

Next tactic:
replace h : (QuotientGroup.mk' _).ker = (1 : B →* B ⧸ f.range).ker := by rw [h]
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
    rw [show (1 : B ⧸ f.range) = (1 : B) from QuotientGroup.mk_one _, QuotientGroup.eq, inv_one,
      one_mul]
    exact ⟨x, rfl⟩
  replace h : (QuotientGroup.mk' _).ker = (1 : B →* B ⧸ f.range).ker := by 

Proof state:
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : 1 = QuotientGroup.mk' (range f)
⊢ ker (QuotientGroup.mk' ?m.29435) = ker 1

Next tactic:
rw [h]
@[to_additive]
theorem range_eq_top_of_cancel {f : A →* B}
    (h : ∀ u v : B →* B ⧸ f.range, u.comp f = v.comp f → u = v) : f.range = ⊤ := by
  specialize h 1 (QuotientGroup.mk' _) _
  · ext1 x
    simp only [one_apply, coe_comp, coe_mk', Function.comp_apply]
    rw [show (1 : B ⧸ f.range) = (1 : B) from QuotientGroup.mk_one _, QuotientGroup.eq, inv_one,
      one_mul]
    exact ⟨x, rfl⟩
  replace h : (QuotientGroup.mk' _).ker = (1 : B →* B ⧸ f.range).ker := by rw [h]
  

Proof state:
A : Type u
B : Type v
inst✝¹ : CommGroup A
inst✝ : CommGroup B
f : A →* B
h : ker (QuotientGroup.mk' (range f)) = ker 1
⊢ range f = ⊤

Next tactic:
rwa [ker_one, QuotientGroup.ker_mk'] at h
instance : SMul B X' where
  smul b x :=
    match x with
    | fromCoset y => fromCoset ⟨b • y, by
          

Proof state:
A B : GroupCat
f : A ⟶ B
b : ↑B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ b • ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f)

Next tactic:
rw [← y.2.choose_spec, leftCoset_assoc]
instance : SMul B X' where
  smul b x :=
    match x with
    | fromCoset y => fromCoset ⟨b • y, by
          rw [← y.2.choose_spec, leftCoset_assoc]
          -- Porting note: should we make `Bundled.α` reducible?
          

Proof state:
A B : GroupCat
f : A ⟶ B
b : ↑B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ (b * Exists.choose (_ : ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f))) • ↑(MonoidHom.range f) ∈
    Set.range fun x => x • ↑(MonoidHom.range f)

Next tactic:
let b' : B := y.2.choose
instance : SMul B X' where
  smul b x :=
    match x with
    | fromCoset y => fromCoset ⟨b • y, by
          rw [← y.2.choose_spec, leftCoset_assoc]
          -- Porting note: should we make `Bundled.α` reducible?
          let b' : B := y.2.choose
          

Proof state:
A B : GroupCat
f : A ⟶ B
b : ↑B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
b' : ↑B := Exists.choose (_ : ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f))
⊢ (b * Exists.choose (_ : ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f))) • ↑(MonoidHom.range f) ∈
    Set.range fun x => x • ↑(MonoidHom.range f)

Next tactic:
use b * b'
theorem mul_smul (b b' : B) (x : X') : (b * b') • x = b • b' • x :=
  match x with
  | fromCoset y => by
    

Proof state:
A B : GroupCat
f : A ⟶ B
b b' : ↑B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ (b * b') • fromCoset y = b • b' • fromCoset y

Next tactic:
change fromCoset _ = fromCoset _
theorem mul_smul (b b' : B) (x : X') : (b * b') • x = b • b' • x :=
  match x with
  | fromCoset y => by
    change fromCoset _ = fromCoset _
    

Proof state:
A B : GroupCat
f : A ⟶ B
b b' : ↑B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ fromCoset { val := (b * b') • ↑y, property := (_ : (b * b') • ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f)) } =
    fromCoset
      { val := b • ↑{ val := b' • ↑y, property := (_ : b' • ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f)) },
        property :=
          (_ :
            b • ↑{ val := b' • ↑y, property := (_ : b' • ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f)) } ∈
              Set.range fun x => x • ↑(MonoidHom.range f)) }

Next tactic:
simp only [leftCoset_assoc]
theorem one_smul (x : X') : (1 : B) • x = x :=
  match x with
  | fromCoset y => by
    

Proof state:
A B : GroupCat
f : A ⟶ B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ 1 • fromCoset y = fromCoset y

Next tactic:
change fromCoset _ = fromCoset _
theorem one_smul (x : X') : (1 : B) • x = x :=
  match x with
  | fromCoset y => by
    change fromCoset _ = fromCoset _
    

Proof state:
A B : GroupCat
f : A ⟶ B
x : X'
y : ↑(Set.range fun x => x • ↑(MonoidHom.range f))
⊢ fromCoset { val := 1 • ↑y, property := (_ : 1 • ↑y ∈ Set.range fun x => x • ↑(MonoidHom.range f)) } = fromCoset y

Next tactic:
simp only [one_leftCoset, Subtype.ext_iff_val]
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  

Proof state:
A B : GroupCat
f : A ⟶ B
b : ↑B
hb : b ∈ MonoidHom.range f
⊢ fromCoset
      { val := b • ↑(MonoidHom.range f),
        property := (_ : ∃ y, (fun x => x • ↑(MonoidHom.range f)) y = b • ↑(MonoidHom.range f)) } =
    fromCoset
      { val := ↑(MonoidHom.range f),
        property := (_ : ∃ y, (fun x => x • ↑(MonoidHom.range f)) y = ↑(MonoidHom.range f)) }

Next tactic:
congr
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  congr
  

Proof state:
case e_a.e_val
A B : GroupCat
f : A ⟶ B
b : ↑B
hb : b ∈ MonoidHom.range f
⊢ b • ↑(MonoidHom.range f) = ↑(MonoidHom.range f)

Next tactic:
let b : B.α := b
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  congr
  let b : B.α := b
  

Proof state:
case e_a.e_val
A B : GroupCat
f : A ⟶ B
b✝ : ↑B
hb : b✝ ∈ MonoidHom.range f
b : ↑B := b✝
⊢ b✝ • ↑(MonoidHom.range f) = ↑(MonoidHom.range f)

Next tactic:
change b • (f.range : Set B) = f.range
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  congr
  let b : B.α := b
  change b • (f.range : Set B) = f.range
  

Proof state:
case e_a.e_val
A B : GroupCat
f : A ⟶ B
b✝ : ↑B
hb : b✝ ∈ MonoidHom.range f
b : ↑B := b✝
⊢ b • ↑(MonoidHom.range f) = ↑(MonoidHom.range f)

Next tactic:
nth_rw 2 [show (f.range : Set B.α) = (1 : B) • f.range from (one_leftCoset _).symm]
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  congr
  let b : B.α := b
  change b • (f.range : Set B) = f.range
  nth_rw 2 [show (f.range : Set B.α) = (1 : B) • f.range from (one_leftCoset _).symm]
  

Proof state:
case e_a.e_val
A B : GroupCat
f : A ⟶ B
b✝ : ↑B
hb : b✝ ∈ MonoidHom.range f
b : ↑B := b✝
⊢ b • ↑(MonoidHom.range f) = 1 • ↑(MonoidHom.range f)

Next tactic:
rw [leftCoset_eq_iff, mul_one]
theorem fromCoset_eq_of_mem_range {b : B} (hb : b ∈ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ = fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  congr
  let b : B.α := b
  change b • (f.range : Set B) = f.range
  nth_rw 2 [show (f.range : Set B.α) = (1 : B) • f.range from (one_leftCoset _).symm]
  rw [leftCoset_eq_iff, mul_one]
  

Proof state:
case e_a.e_val
A B : GroupCat
f : A ⟶ B
b✝ : ↑B
hb : b✝ ∈ MonoidHom.range f
b : ↑B := b✝
⊢ b⁻¹ ∈ MonoidHom.range f

Next tactic:
exact Subgroup.inv_mem _ hb
theorem fromCoset_ne_of_nin_range {b : B} (hb : b ∉ f.range) :
    fromCoset ⟨b • ↑f.range, b, rfl⟩ ≠ fromCoset ⟨f.range, 1, one_leftCoset _⟩ := by
  

Proof state:
A B : GroupCat
f : A ⟶ B
b : ↑B
hb : b ∉ MonoidHom.range f
⊢ fromCoset
      { val := b • ↑(MonoidHom.range f),
        property := (_ : ∃ y, (fun x => x • ↑(MonoidHom.range f)) y = b • ↑(MonoidHom.range f)) } ≠
    fromCoset
      { val := ↑(MonoidHom.range f),
        property := (_ : ∃ y, (fun x => x • ↑(MonoidHom.range f)) y = ↑(MonoidHom.range f)) }

Next tactic:
intro r