l3lab/ntp-mathlib huggingface dataset:
/-- The smallest congruence relation containing a binary relation `r` is contained in any
    congruence relation containing `r`. -/
theorem ringConGen_le {r : R → R → Prop} {c : RingCon R}
    (h : ∀ x y, r x y → c x y) : ringConGen r ≤ c := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
r : R → R → Prop
c : RingCon R
h : ∀ (x y : R), r x y → c x y
⊢ ringConGen r ≤ c

Next tactic:
rw [ringConGen_eq]
/-- The smallest congruence relation containing a binary relation `r` is contained in any
    congruence relation containing `r`. -/
theorem ringConGen_le {r : R → R → Prop} {c : RingCon R}
    (h : ∀ x y, r x y → c x y) : ringConGen r ≤ c := by
  rw [ringConGen_eq]; 

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
r : R → R → Prop
c : RingCon R
h : ∀ (x y : R), r x y → c x y
⊢ sInf {s | ∀ (x y : R), r x y → s x y} ≤ c

Next tactic:
exact sInf_le h
/-- Congruence relations equal the smallest congruence relation in which they are contained. -/
theorem ringConGen_of_ringCon (c : RingCon R) : ringConGen c = c :=
  le_antisymm (by 

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c : RingCon R
⊢ ringConGen ⇑c ≤ c

Next tactic:
rw [ringConGen_eq]
/-- Congruence relations equal the smallest congruence relation in which they are contained. -/
theorem ringConGen_of_ringCon (c : RingCon R) : ringConGen c = c :=
  le_antisymm (by rw [ringConGen_eq]; 

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c : RingCon R
⊢ sInf {s | ∀ (x y : R), c x y → s x y} ≤ c

Next tactic:
exact sInf_le fun _ _ => id
/-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing
    the binary relation '`x` is related to `y` by `c` or `d`'. -/
theorem sup_eq_ringConGen (c d : RingCon R) : c ⊔ d = ringConGen fun x y => c x y ∨ d x y := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c d : RingCon R
⊢ c ⊔ d = ringConGen fun x y => c x y ∨ d x y

Next tactic:
rw [ringConGen_eq]
/-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing
    the binary relation '`x` is related to `y` by `c` or `d`'. -/
theorem sup_eq_ringConGen (c d : RingCon R) : c ⊔ d = ringConGen fun x y => c x y ∨ d x y := by
  rw [ringConGen_eq]
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c d : RingCon R
⊢ c ⊔ d = sInf {s | ∀ (x y : R), c x y ∨ d x y → s x y}

Next tactic:
apply congr_arg sInf
/-- The supremum of congruence relations `c, d` equals the smallest congruence relation containing
    the binary relation '`x` is related to `y` by `c` or `d`'. -/
theorem sup_eq_ringConGen (c d : RingCon R) : c ⊔ d = ringConGen fun x y => c x y ∨ d x y := by
  rw [ringConGen_eq]
  apply congr_arg sInf
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c d : RingCon R
⊢ {x | c ≤ x ∧ d ≤ x} = {s | ∀ (x y : R), c x y ∨ d x y → s x y}

Next tactic:
simp only [le_def, or_imp, ← forall_and]
/-- The supremum of two congruence relations equals the smallest congruence relation containing
    the supremum of the underlying binary operations. -/
theorem sup_def {c d : RingCon R} : c ⊔ d = ringConGen (⇑c ⊔ ⇑d) := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c d : RingCon R
⊢ c ⊔ d = ringConGen (⇑c ⊔ ⇑d)

Next tactic:
rw [sup_eq_ringConGen]
/-- The supremum of two congruence relations equals the smallest congruence relation containing
    the supremum of the underlying binary operations. -/
theorem sup_def {c d : RingCon R} : c ⊔ d = ringConGen (⇑c ⊔ ⇑d) := by
  rw [sup_eq_ringConGen]; 

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
c d : RingCon R
⊢ (ringConGen fun x y => c x y ∨ d x y) = ringConGen (⇑c ⊔ ⇑d)

Next tactic:
rfl
/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation
    containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by
    `c`'. -/
theorem sSup_eq_ringConGen (S : Set (RingCon R)) :
    sSup S = ringConGen fun x y => ∃ c : RingCon R, c ∈ S ∧ c x y := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
⊢ sSup S = ringConGen fun x y => ∃ c ∈ S, c x y

Next tactic:
rw [ringConGen_eq]
/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation
    containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by
    `c`'. -/
theorem sSup_eq_ringConGen (S : Set (RingCon R)) :
    sSup S = ringConGen fun x y => ∃ c : RingCon R, c ∈ S ∧ c x y := by
  rw [ringConGen_eq]
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
⊢ sSup S = sInf {s | ∀ (x y : R), (∃ c ∈ S, c x y) → s x y}

Next tactic:
apply congr_arg sInf
/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation
    containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by
    `c`'. -/
theorem sSup_eq_ringConGen (S : Set (RingCon R)) :
    sSup S = ringConGen fun x y => ∃ c : RingCon R, c ∈ S ∧ c x y := by
  rw [ringConGen_eq]
  apply congr_arg sInf
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
⊢ upperBounds S = {s | ∀ (x y : R), (∃ c ∈ S, c x y) → s x y}

Next tactic:
ext
/-- The supremum of a set of congruence relations `S` equals the smallest congruence relation
    containing the binary relation 'there exists `c ∈ S` such that `x` is related to `y` by
    `c`'. -/
theorem sSup_eq_ringConGen (S : Set (RingCon R)) :
    sSup S = ringConGen fun x y => ∃ c : RingCon R, c ∈ S ∧ c x y := by
  rw [ringConGen_eq]
  apply congr_arg sInf
  ext
  

Proof state:
case h
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
x✝ : RingCon R
⊢ x✝ ∈ upperBounds S ↔ x✝ ∈ {s | ∀ (x y : R), (∃ c ∈ S, c x y) → s x y}

Next tactic:
exact ⟨fun h _ _ ⟨r, hr⟩ => h hr.1 hr.2, fun h r hS _ _ hr => h _ _ ⟨r, hS, hr⟩⟩
/-- The supremum of a set of congruence relations is the same as the smallest congruence relation
    containing the supremum of the set's image under the map to the underlying binary relation. -/
theorem sSup_def {S : Set (RingCon R)} :
    sSup S = ringConGen (sSup (@Set.image (RingCon R) (R → R → Prop) (⇑) S)) := by
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
⊢ sSup S = ringConGen (sSup (FunLike.coe '' S))

Next tactic:
rw [sSup_eq_ringConGen, sSup_image]
/-- The supremum of a set of congruence relations is the same as the smallest congruence relation
    containing the supremum of the set's image under the map to the underlying binary relation. -/
theorem sSup_def {S : Set (RingCon R)} :
    sSup S = ringConGen (sSup (@Set.image (RingCon R) (R → R → Prop) (⇑) S)) := by
  rw [sSup_eq_ringConGen, sSup_image]
  

Proof state:
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
⊢ (ringConGen fun x y => ∃ c ∈ S, c x y) = ringConGen (⨆ a ∈ S, ⇑a)

Next tactic:
congr with (x y)
/-- The supremum of a set of congruence relations is the same as the smallest congruence relation
    containing the supremum of the set's image under the map to the underlying binary relation. -/
theorem sSup_def {S : Set (RingCon R)} :
    sSup S = ringConGen (sSup (@Set.image (RingCon R) (R → R → Prop) (⇑) S)) := by
  rw [sSup_eq_ringConGen, sSup_image]
  congr with (x y)
  

Proof state:
case e_r.h.h.a
α : Type u_1
R : Type u_2
inst✝¹ : Add R
inst✝ : Mul R
S : Set (RingCon R)
x y : R
⊢ (∃ c ∈ S, c x y) ↔ iSup (fun a => ⨆ (_ : a ∈ S), ⇑a) x y

Next tactic:
simp only [sSup_image, iSup_apply, iSup_Prop_eq, exists_prop, rel_eq_coe]
/-- Characterizing uniformities associated to a (generalized) distance function `D`
in terms of the elements of the uniformity. -/
theorem uniformity_dist_of_mem_uniformity [LinearOrder β] {U : Filter (α × α)} (z : β)
    (D : α → α → β) (H : ∀ s, s ∈ U ↔ ∃ ε > z, ∀ {a b : α}, D a b < ε → (a, b) ∈ s) :
    U = ⨅ ε > z, 𝓟 { p : α × α | D p.1 p.2 < ε } :=
  HasBasis.eq_biInf ⟨fun s => by 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : LinearOrder β
U : Filter (α × α)
z : β
D : α → α → β
H : ∀ (s : Set (α × α)), s ∈ U ↔ ∃ ε > z, ∀ {a b : α}, D a b < ε → (a, b) ∈ s
s : Set (α × α)
⊢ s ∈ U ↔ ∃ i > z, {p | D p.1 p.2 < i} ⊆ s

Next tactic:
simp only [H, subset_def, Prod.forall, mem_setOf]
/-- Triangle inequality for the extended distance -/
theorem edist_triangle_left (x y z : α) : edist x y ≤ edist z x + edist z y := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
⊢ edist x y ≤ edist z x + edist z y

Next tactic:
rw [edist_comm z]
/-- Triangle inequality for the extended distance -/
theorem edist_triangle_left (x y z : α) : edist x y ≤ edist z x + edist z y := by
  rw [edist_comm z]; 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
⊢ edist x y ≤ edist x z + edist z y

Next tactic:
apply edist_triangle
theorem edist_triangle_right (x y z : α) : edist x y ≤ edist x z + edist y z := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
⊢ edist x y ≤ edist x z + edist y z

Next tactic:
rw [edist_comm y]
theorem edist_triangle_right (x y z : α) : edist x y ≤ edist x z + edist y z := by
  rw [edist_comm y]; 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
⊢ edist x y ≤ edist x z + edist z y

Next tactic:
apply edist_triangle
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist x z = edist y z

Next tactic:
apply le_antisymm
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  apply le_antisymm
  · 

Proof state:
case a
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist x z ≤ edist y z

Next tactic:
rw [← zero_add (edist y z), ← h]
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  apply le_antisymm
  · rw [← zero_add (edist y z), ← h]
    

Proof state:
case a
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist x z ≤ edist x y + edist y z

Next tactic:
apply edist_triangle
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  apply le_antisymm
  · rw [← zero_add (edist y z), ← h]
    apply edist_triangle
  · 

Proof state:
case a
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist y z ≤ edist x z

Next tactic:
rw [edist_comm] at h
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  apply le_antisymm
  · rw [← zero_add (edist y z), ← h]
    apply edist_triangle
  · rw [edist_comm] at h
    

Proof state:
case a
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist y x = 0
⊢ edist y z ≤ edist x z

Next tactic:
rw [← zero_add (edist x z), ← h]
theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by
  apply le_antisymm
  · rw [← zero_add (edist y z), ← h]
    apply edist_triangle
  · rw [edist_comm] at h
    rw [← zero_add (edist x z), ← h]
    

Proof state:
case a
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist y x = 0
⊢ edist y z ≤ edist y x + edist x z

Next tactic:
apply edist_triangle
theorem edist_congr_left {x y z : α} (h : edist x y = 0) : edist z x = edist z y := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist z x = edist z y

Next tactic:
rw [edist_comm z x, edist_comm z y]
theorem edist_congr_left {x y z : α} (h : edist x y = 0) : edist z x = edist z y := by
  rw [edist_comm z x, edist_comm z y]
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
h : edist x y = 0
⊢ edist x z = edist y z

Next tactic:
apply edist_congr_right h
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n : ℕ
h : m ≤ n
⊢ edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))

Next tactic:
induction n, h using Nat.le_induction
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  

Proof state:
case base
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n : ℕ
⊢ edist (f m) (f m) ≤ ∑ i in Finset.Ico m m, edist (f i) (f (i + 1))
case succ
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n n✝ : ℕ
hn✝ : m ≤ n✝
a✝ : edist (f m) (f n✝) ≤ ∑ i in Finset.Ico m n✝, edist (f i) (f (i + 1))
⊢ edist (f m) (f (n✝ + 1)) ≤ ∑ i in Finset.Ico m (n✝ + 1), edist (f i) (f (i + 1))

Next tactic:
case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n : ℕ
⊢ edist (f m) (f m) ≤ ∑ i in Finset.Ico m m, edist (f i) (f (i + 1))

Next tactic:
case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n : ℕ
⊢ edist (f m) (f m) ≤ ∑ i in Finset.Ico m m, edist (f i) (f (i + 1))

Next tactic:
rw [Finset.Ico_self, Finset.sum_empty, edist_self]
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  

Proof state:
case succ
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n n✝ : ℕ
hn✝ : m ≤ n✝
a✝ : edist (f m) (f n✝) ≤ ∑ i in Finset.Ico m n✝, edist (f i) (f (i + 1))
⊢ edist (f m) (f (n✝ + 1)) ≤ ∑ i in Finset.Ico m (n✝ + 1), edist (f i) (f (i + 1))

Next tactic:
case succ n hle ihn =>
    calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp }
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n✝ n : ℕ
hle : m ≤ n
ihn : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))
⊢ edist (f m) (f (n + 1)) ≤ ∑ i in Finset.Ico m (n + 1), edist (f i) (f (i + 1))

Next tactic:
case succ n hle ihn =>
    calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp }
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  case succ n hle ihn =>
    

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n✝ n : ℕ
hle : m ≤ n
ihn : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))
⊢ edist (f m) (f (n + 1)) ≤ ∑ i in Finset.Ico m (n + 1), edist (f i) (f (i + 1))

Next tactic:
calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp }
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  case succ n hle ihn =>
    calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n✝ n : ℕ
hle : m ≤ n
ihn : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))
⊢ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) + edist (f n) (f (n + 1)) =
    ∑ i in Finset.Ico m (n + 1), edist (f i) (f (i + 1))

Next tactic:
{ rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp }
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  case succ n hle ihn =>
    calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      { 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n✝ n : ℕ
hle : m ≤ n
ihn : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))
⊢ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) + edist (f n) (f (n + 1)) =
    ∑ i in Finset.Ico m (n + 1), edist (f i) (f (i + 1))

Next tactic:
rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]
/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/
theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) :
    edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1)) := by
  induction n, h using Nat.le_induction
  case base => rw [Finset.Ico_self, Finset.sum_empty, edist_self]
  case succ n hle ihn =>
    calc
      edist (f m) (f (n + 1)) ≤ edist (f m) (f n) + edist (f n) (f (n + 1)) := edist_triangle _ _ _
      _ ≤ (∑ i in Finset.Ico m n, _) + _ := add_le_add ihn le_rfl
      _ = ∑ i in Finset.Ico m (n + 1), _ := by
      { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
f : ℕ → α
m n✝ n : ℕ
hle : m ≤ n
ihn : edist (f m) (f n) ≤ ∑ i in Finset.Ico m n, edist (f i) (f (i + 1))
⊢ n ∉ Finset.Ico m n

Next tactic:
simp
/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers
accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`.

For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`,
`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/
protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞}
    (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) :
    (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by
  

Proof state:
α : Type u
β✝ : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
β : Type u_2
p : β → Prop
f : β → ℝ≥0∞
hf₀ : ∀ (x : β), p x → 0 < f x
hf : ∀ (ε : ℝ≥0∞), 0 < ε → ∃ x, p x ∧ f x ≤ ε
⊢ HasBasis (𝓤 α) p fun x => {p | edist p.1 p.2 < f x}

Next tactic:
refine' ⟨fun s => uniformity_basis_edist.mem_iff.trans _⟩
/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers
accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`.

For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`,
`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/
protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞}
    (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) :
    (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by
  refine' ⟨fun s => uniformity_basis_edist.mem_iff.trans _⟩
  

Proof state:
α : Type u
β✝ : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
β : Type u_2
p : β → Prop
f : β → ℝ≥0∞
hf₀ : ∀ (x : β), p x → 0 < f x
hf : ∀ (ε : ℝ≥0∞), 0 < ε → ∃ x, p x ∧ f x ≤ ε
s : Set (α × α)
⊢ (∃ i, 0 < i ∧ {p | edist p.1 p.2 < i} ⊆ s) ↔ ∃ i, p i ∧ {p | edist p.1 p.2 < f i} ⊆ s

Next tactic:
constructor
/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers
accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`.

For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`,
`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/
protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞}
    (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) :
    (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by
  refine' ⟨fun s => uniformity_basis_edist.mem_iff.trans _⟩
  constructor
  · 

Proof state:
case mp
α : Type u
β✝ : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
β : Type u_2
p : β → Prop
f : β → ℝ≥0∞
hf₀ : ∀ (x : β), p x → 0 < f x
hf : ∀ (ε : ℝ≥0∞), 0 < ε → ∃ x, p x ∧ f x ≤ ε
s : Set (α × α)
⊢ (∃ i, 0 < i ∧ {p | edist p.1 p.2 < i} ⊆ s) → ∃ i, p i ∧ {p | edist p.1 p.2 < f i} ⊆ s

Next tactic:
rintro ⟨ε, ε₀, hε⟩
/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers
accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`.

For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`,
`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/
protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞}
    (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) :
    (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by
  refine' ⟨fun s => uniformity_basis_edist.mem_iff.trans _⟩
  constructor
  · rintro ⟨ε, ε₀, hε⟩
    

Proof state:
case mp.intro.intro
α : Type u
β✝ : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
β : Type u_2
p : β → Prop
f : β → ℝ≥0∞
hf₀ : ∀ (x : β), p x → 0 < f x
hf : ∀ (ε : ℝ≥0∞), 0 < ε → ∃ x, p x ∧ f x ≤ ε
s : Set (α × α)
ε : ℝ≥0∞
ε₀ : 0 < ε
hε : {p | edist p.1 p.2 < ε} ⊆ s
⊢ ∃ i, p i ∧ {p | edist p.1 p.2 < f i} ⊆ s

Next tactic:
rcases hf ε ε₀ with ⟨i, hi, H⟩