l3lab/ntp-mathlib huggingface dataset:
/-- The diameter of a union is controlled by the diameter of the sets, and the edistance
between two points in the sets. -/
theorem diam_union {t : Set α} (xs : x ∈ s) (yt : y ∈ t) :
    diam (s ∪ t) ≤ diam s + edist x y + diam t := by
  have A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t := fun a ha b hb =>
    calc
      edist a b ≤ edist a x + edist x y + edist y b := edist_triangle4 _ _ _ _
      _ ≤ diam s + edist x y + diam t :=
        add_le_add (add_le_add (edist_le_diam_of_mem ha xs) le_rfl) (edist_le_diam_of_mem yt hb)
  refine' diam_le fun a ha b hb => _
  cases' (mem_union _ _ _).1 ha with h'a h'a <;> cases' (mem_union _ _ _).1 hb with h'b h'b
  · calc
      edist a b ≤ diam s := edist_le_diam_of_mem h'a h'b
      _ ≤ diam s + (edist x y + diam t) := le_self_add
      _ = diam s + edist x y + diam t := (add_assoc _ _ _).symm
  · exact A a h'a b h'b
  · 

Proof state:
case inr.inl
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
ε ε₁ ε₂ : ℝ≥0∞
s t✝ t : Set α
xs : x ∈ s
yt : y ∈ t
A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t
a : α
ha : a ∈ s ∪ t
b : α
hb : b ∈ s ∪ t
h'a : a ∈ t
h'b : b ∈ s
⊢ edist a b ≤ diam s + edist x y + diam t

Next tactic:
have Z := A b h'b a h'a
/-- The diameter of a union is controlled by the diameter of the sets, and the edistance
between two points in the sets. -/
theorem diam_union {t : Set α} (xs : x ∈ s) (yt : y ∈ t) :
    diam (s ∪ t) ≤ diam s + edist x y + diam t := by
  have A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t := fun a ha b hb =>
    calc
      edist a b ≤ edist a x + edist x y + edist y b := edist_triangle4 _ _ _ _
      _ ≤ diam s + edist x y + diam t :=
        add_le_add (add_le_add (edist_le_diam_of_mem ha xs) le_rfl) (edist_le_diam_of_mem yt hb)
  refine' diam_le fun a ha b hb => _
  cases' (mem_union _ _ _).1 ha with h'a h'a <;> cases' (mem_union _ _ _).1 hb with h'b h'b
  · calc
      edist a b ≤ diam s := edist_le_diam_of_mem h'a h'b
      _ ≤ diam s + (edist x y + diam t) := le_self_add
      _ = diam s + edist x y + diam t := (add_assoc _ _ _).symm
  · exact A a h'a b h'b
  · have Z := A b h'b a h'a
    

Proof state:
case inr.inl
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
ε ε₁ ε₂ : ℝ≥0∞
s t✝ t : Set α
xs : x ∈ s
yt : y ∈ t
A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t
a : α
ha : a ∈ s ∪ t
b : α
hb : b ∈ s ∪ t
h'a : a ∈ t
h'b : b ∈ s
Z : edist b a ≤ diam s + edist x y + diam t
⊢ edist a b ≤ diam s + edist x y + diam t

Next tactic:
rwa [edist_comm] at Z
/-- The diameter of a union is controlled by the diameter of the sets, and the edistance
between two points in the sets. -/
theorem diam_union {t : Set α} (xs : x ∈ s) (yt : y ∈ t) :
    diam (s ∪ t) ≤ diam s + edist x y + diam t := by
  have A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t := fun a ha b hb =>
    calc
      edist a b ≤ edist a x + edist x y + edist y b := edist_triangle4 _ _ _ _
      _ ≤ diam s + edist x y + diam t :=
        add_le_add (add_le_add (edist_le_diam_of_mem ha xs) le_rfl) (edist_le_diam_of_mem yt hb)
  refine' diam_le fun a ha b hb => _
  cases' (mem_union _ _ _).1 ha with h'a h'a <;> cases' (mem_union _ _ _).1 hb with h'b h'b
  · calc
      edist a b ≤ diam s := edist_le_diam_of_mem h'a h'b
      _ ≤ diam s + (edist x y + diam t) := le_self_add
      _ = diam s + edist x y + diam t := (add_assoc _ _ _).symm
  · exact A a h'a b h'b
  · have Z := A b h'b a h'a
    rwa [edist_comm] at Z
  · 

Proof state:
case inr.inr
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
ε ε₁ ε₂ : ℝ≥0∞
s t✝ t : Set α
xs : x ∈ s
yt : y ∈ t
A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t
a : α
ha : a ∈ s ∪ t
b : α
hb : b ∈ s ∪ t
h'a : a ∈ t
h'b : b ∈ t
⊢ edist a b ≤ diam s + edist x y + diam t

Next tactic:
calc
      edist a b ≤ diam t := edist_le_diam_of_mem h'a h'b
      _ ≤ diam s + edist x y + diam t := le_add_self
theorem diam_union' {t : Set α} (h : (s ∩ t).Nonempty) : diam (s ∪ t) ≤ diam s + diam t := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x y z : α
ε ε₁ ε₂ : ℝ≥0∞
s t✝ t : Set α
h : Set.Nonempty (s ∩ t)
⊢ diam (s ∪ t) ≤ diam s + diam t

Next tactic:
let ⟨x, ⟨xs, xt⟩⟩ := h
theorem diam_union' {t : Set α} (h : (s ∩ t).Nonempty) : diam (s ∪ t) ≤ diam s + diam t := by
  let ⟨x, ⟨xs, xt⟩⟩ := h
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝ : PseudoEMetricSpace α
x✝ y z : α
ε ε₁ ε₂ : ℝ≥0∞
s t✝ t : Set α
h : Set.Nonempty (s ∩ t)
x : α
xs : x ∈ s
xt : x ∈ t
⊢ diam (s ∪ t) ≤ diam s + diam t

Next tactic:
simpa using diam_union xs xt
theorem diam_pi_le_of_le {π : β → Type*} [Fintype β] [∀ b, PseudoEMetricSpace (π b)]
    {s : ∀ b : β, Set (π b)} {c : ℝ≥0∞} (h : ∀ b, diam (s b) ≤ c) : diam (Set.pi univ s) ≤ c := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
x y z : α
ε ε₁ ε₂ : ℝ≥0∞
s✝ t : Set α
π : β → Type u_2
inst✝¹ : Fintype β
inst✝ : (b : β) → PseudoEMetricSpace (π b)
s : (b : β) → Set (π b)
c : ℝ≥0∞
h : ∀ (b : β), diam (s b) ≤ c
⊢ diam (Set.pi univ s) ≤ c

Next tactic:
refine diam_le fun x hx y hy => edist_pi_le_iff.mpr ?_
theorem diam_pi_le_of_le {π : β → Type*} [Fintype β] [∀ b, PseudoEMetricSpace (π b)]
    {s : ∀ b : β, Set (π b)} {c : ℝ≥0∞} (h : ∀ b, diam (s b) ≤ c) : diam (Set.pi univ s) ≤ c := by
  refine diam_le fun x hx y hy => edist_pi_le_iff.mpr ?_
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
x✝ y✝ z : α
ε ε₁ ε₂ : ℝ≥0∞
s✝ t : Set α
π : β → Type u_2
inst✝¹ : Fintype β
inst✝ : (b : β) → PseudoEMetricSpace (π b)
s : (b : β) → Set (π b)
c : ℝ≥0∞
h : ∀ (b : β), diam (s b) ≤ c
x : (i : β) → π i
hx : x ∈ Set.pi univ s
y : (i : β) → π i
hy : y ∈ Set.pi univ s
⊢ ∀ (b : β), edist (x b) (y b) ≤ c

Next tactic:
rw [mem_univ_pi] at hx hy
theorem diam_pi_le_of_le {π : β → Type*} [Fintype β] [∀ b, PseudoEMetricSpace (π b)]
    {s : ∀ b : β, Set (π b)} {c : ℝ≥0∞} (h : ∀ b, diam (s b) ≤ c) : diam (Set.pi univ s) ≤ c := by
  refine diam_le fun x hx y hy => edist_pi_le_iff.mpr ?_
  rw [mem_univ_pi] at hx hy
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
x✝ y✝ z : α
ε ε₁ ε₂ : ℝ≥0∞
s✝ t : Set α
π : β → Type u_2
inst✝¹ : Fintype β
inst✝ : (b : β) → PseudoEMetricSpace (π b)
s : (b : β) → Set (π b)
c : ℝ≥0∞
h : ∀ (b : β), diam (s b) ≤ c
x : (i : β) → π i
hx : ∀ (i : β), x i ∈ s i
y : (i : β) → π i
hy : ∀ (i : β), y i ∈ s i
⊢ ∀ (b : β), edist (x b) (y b) ≤ c

Next tactic:
exact fun b => diam_le_iff.1 (h b) (x b) (hx b) (y b) (hy b)
@[simp]
theorem edist_pos {x y : γ} : 0 < edist x y ↔ x ≠ y := by 

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝¹ : PseudoEMetricSpace α
γ : Type w
inst✝ : EMetricSpace γ
x y : γ
⊢ 0 < edist x y ↔ x ≠ y

Next tactic:
simp [← not_le]
/-- A map between emetric spaces is a uniform embedding if and only if the edistance between `f x`
and `f y` is controlled in terms of the distance between `x` and `y` and conversely. -/
theorem EMetric.uniformEmbedding_iff' [EMetricSpace β] {f : γ → β} :
    UniformEmbedding f ↔
      (∀ ε > 0, ∃ δ > 0, ∀ {a b : γ}, edist a b < δ → edist (f a) (f b) < ε) ∧
        ∀ δ > 0, ∃ ε > 0, ∀ {a b : γ}, edist (f a) (f b) < ε → edist a b < δ := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : EMetricSpace β
f : γ → β
⊢ UniformEmbedding f ↔
    (∀ ε > 0, ∃ δ > 0, ∀ {a b : γ}, edist a b < δ → edist (f a) (f b) < ε) ∧
      ∀ δ > 0, ∃ ε > 0, ∀ {a b : γ}, edist (f a) (f b) < ε → edist a b < δ

Next tactic:
rw [uniformEmbedding_iff_uniformInducing, uniformInducing_iff, uniformContinuous_iff]
/-- A compact set in an emetric space is separable, i.e., it is the closure of a countable set. -/
theorem countable_closure_of_compact {s : Set γ} (hs : IsCompact s) :
    ∃ t, t ⊆ s ∧ t.Countable ∧ s = closure t := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝¹ : PseudoEMetricSpace α
γ : Type w
inst✝ : EMetricSpace γ
s : Set γ
hs : IsCompact s
⊢ ∃ t ⊆ s, Set.Countable t ∧ s = closure t

Next tactic:
rcases subset_countable_closure_of_compact hs with ⟨t, hts, htc, hsub⟩
/-- A compact set in an emetric space is separable, i.e., it is the closure of a countable set. -/
theorem countable_closure_of_compact {s : Set γ} (hs : IsCompact s) :
    ∃ t, t ⊆ s ∧ t.Countable ∧ s = closure t := by
  rcases subset_countable_closure_of_compact hs with ⟨t, hts, htc, hsub⟩
  

Proof state:
case intro.intro.intro
α : Type u
β : Type v
X : Type u_1
inst✝¹ : PseudoEMetricSpace α
γ : Type w
inst✝ : EMetricSpace γ
s : Set γ
hs : IsCompact s
t : Set γ
hts : t ⊆ s
htc : Set.Countable t
hsub : s ⊆ closure t
⊢ ∃ t ⊆ s, Set.Countable t ∧ s = closure t

Next tactic:
exact ⟨t, hts, htc, hsub.antisymm (closure_minimal hts hs.isClosed)⟩
theorem diam_pos_iff : 0 < diam s ↔ s.Nontrivial := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝¹ : PseudoEMetricSpace α
γ : Type w
inst✝ : EMetricSpace γ
s : Set γ
⊢ 0 < diam s ↔ Set.Nontrivial s

Next tactic:
simp only [pos_iff_ne_zero, Ne.def, diam_eq_zero_iff, Set.not_subsingleton_iff]
theorem diam_pos_iff' : 0 < diam s ↔ ∃ x ∈ s, ∃ y ∈ s, x ≠ y := by
  

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝¹ : PseudoEMetricSpace α
γ : Type w
inst✝ : EMetricSpace γ
s : Set γ
⊢ 0 < diam s ↔ ∃ x ∈ s, ∃ y ∈ s, x ≠ y

Next tactic:
simp only [diam_pos_iff, Set.Nontrivial, exists_prop]
instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient X) :=
  @EMetricSpace.ofT0PseudoEMetricSpace (UniformSpace.SeparationQuotient X)
    { edist_self := fun x => Quotient.inductionOn' x edist_self,
      edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm,
      edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle,
      toUniformSpace := inferInstance,
      uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε =>
        iInf_congr $ fun _ => congr_arg 𝓟 <| by
          

Proof state:
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : PseudoEMetricSpace X
ε : ℝ≥0∞
x✝ : 0 < ε
⊢ (fun p => (⟦p.1⟧, ⟦p.2⟧)) '' {p | edist p.1 p.2 < ε} = {p | edist p.1 p.2 < ε}

Next tactic:
ext ⟨⟨x⟩, ⟨y⟩⟩
instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient X) :=
  @EMetricSpace.ofT0PseudoEMetricSpace (UniformSpace.SeparationQuotient X)
    { edist_self := fun x => Quotient.inductionOn' x edist_self,
      edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm,
      edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle,
      toUniformSpace := inferInstance,
      uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε =>
        iInf_congr $ fun _ => congr_arg 𝓟 <| by
          ext ⟨⟨x⟩, ⟨y⟩⟩
          

Proof state:
case h.mk.mk.mk
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : PseudoEMetricSpace X
ε : ℝ≥0∞
x✝ : 0 < ε
fst✝ snd✝ : Quotient (UniformSpace.separationSetoid X)
x y : X
⊢ (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ (fun p => (⟦p.1⟧, ⟦p.2⟧)) '' {p | edist p.1 p.2 < ε} ↔
    (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ {p | edist p.1 p.2 < ε}

Next tactic:
refine ⟨?_, fun h => ⟨(x, y), h, rfl⟩⟩
instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient X) :=
  @EMetricSpace.ofT0PseudoEMetricSpace (UniformSpace.SeparationQuotient X)
    { edist_self := fun x => Quotient.inductionOn' x edist_self,
      edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm,
      edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle,
      toUniformSpace := inferInstance,
      uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε =>
        iInf_congr $ fun _ => congr_arg 𝓟 <| by
          ext ⟨⟨x⟩, ⟨y⟩⟩
          refine ⟨?_, fun h => ⟨(x, y), h, rfl⟩⟩
          

Proof state:
case h.mk.mk.mk
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : PseudoEMetricSpace X
ε : ℝ≥0∞
x✝ : 0 < ε
fst✝ snd✝ : Quotient (UniformSpace.separationSetoid X)
x y : X
⊢ (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ (fun p => (⟦p.1⟧, ⟦p.2⟧)) '' {p | edist p.1 p.2 < ε} →
    (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ {p | edist p.1 p.2 < ε}

Next tactic:
rintro ⟨⟨x', y'⟩, h', h⟩
instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient X) :=
  @EMetricSpace.ofT0PseudoEMetricSpace (UniformSpace.SeparationQuotient X)
    { edist_self := fun x => Quotient.inductionOn' x edist_self,
      edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm,
      edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle,
      toUniformSpace := inferInstance,
      uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε =>
        iInf_congr $ fun _ => congr_arg 𝓟 <| by
          ext ⟨⟨x⟩, ⟨y⟩⟩
          refine ⟨?_, fun h => ⟨(x, y), h, rfl⟩⟩
          rintro ⟨⟨x', y'⟩, h', h⟩
          

Proof state:
case h.mk.mk.mk.intro.mk.intro
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : PseudoEMetricSpace X
ε : ℝ≥0∞
x✝ : 0 < ε
fst✝ snd✝ : Quotient (UniformSpace.separationSetoid X)
x y x' y' : X
h' : (x', y') ∈ {p | edist p.1 p.2 < ε}
h : (fun p => (⟦p.1⟧, ⟦p.2⟧)) (x', y') = (Quot.mk Setoid.r x, Quot.mk Setoid.r y)
⊢ (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ {p | edist p.1 p.2 < ε}

Next tactic:
simp only [Prod.ext_iff] at h
instance [PseudoEMetricSpace X] : EMetricSpace (UniformSpace.SeparationQuotient X) :=
  @EMetricSpace.ofT0PseudoEMetricSpace (UniformSpace.SeparationQuotient X)
    { edist_self := fun x => Quotient.inductionOn' x edist_self,
      edist_comm := fun x y => Quotient.inductionOn₂' x y edist_comm,
      edist_triangle := fun x y z => Quotient.inductionOn₃' x y z edist_triangle,
      toUniformSpace := inferInstance,
      uniformity_edist := (uniformity_basis_edist.map _).eq_biInf.trans $ iInf_congr $ fun ε =>
        iInf_congr $ fun _ => congr_arg 𝓟 <| by
          ext ⟨⟨x⟩, ⟨y⟩⟩
          refine ⟨?_, fun h => ⟨(x, y), h, rfl⟩⟩
          rintro ⟨⟨x', y'⟩, h', h⟩
          simp only [Prod.ext_iff] at h
          

Proof state:
case h.mk.mk.mk.intro.mk.intro
α : Type u
β : Type v
X : Type u_1
inst✝² : PseudoEMetricSpace α
γ : Type w
inst✝¹ : EMetricSpace γ
inst✝ : PseudoEMetricSpace X
ε : ℝ≥0∞
x✝ : 0 < ε
fst✝ snd✝ : Quotient (UniformSpace.separationSetoid X)
x y x' y' : X
h' : (x', y') ∈ {p | edist p.1 p.2 < ε}
h : ⟦x'⟧ = Quot.mk Setoid.r x ∧ ⟦y'⟧ = Quot.mk Setoid.r y
⊢ (Quot.mk Setoid.r x, Quot.mk Setoid.r y) ∈ {p | edist p.1 p.2 < ε}

Next tactic:
rwa [← h.1, ← h.2]
/-- In any concrete category, we can test equality of morphisms by pointwise evaluations.-/
@[ext low] -- Porting note: lowered priority
theorem ConcreteCategory.hom_ext {X Y : C} (f g : X ⟶ Y) (w : ∀ x : X, f x = g x) : f = g := by
  

Proof state:
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X Y : C
f g : X ⟶ Y
w : ∀ (x : (forget C).obj X), f x = g x
⊢ f = g

Next tactic:
apply @Faithful.map_injective C _ (Type w) _ (forget C) _ X Y
/-- In any concrete category, we can test equality of morphisms by pointwise evaluations.-/
@[ext low] -- Porting note: lowered priority
theorem ConcreteCategory.hom_ext {X Y : C} (f g : X ⟶ Y) (w : ∀ x : X, f x = g x) : f = g := by
  apply @Faithful.map_injective C _ (Type w) _ (forget C) _ X Y
  

Proof state:
case a
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X Y : C
f g : X ⟶ Y
w : ∀ (x : (forget C).obj X), f x = g x
⊢ (forget C).map f = (forget C).map g

Next tactic:
dsimp [forget]
/-- In any concrete category, we can test equality of morphisms by pointwise evaluations.-/
@[ext low] -- Porting note: lowered priority
theorem ConcreteCategory.hom_ext {X Y : C} (f g : X ⟶ Y) (w : ∀ x : X, f x = g x) : f = g := by
  apply @Faithful.map_injective C _ (Type w) _ (forget C) _ X Y
  dsimp [forget]
  

Proof state:
case a
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X Y : C
f g : X ⟶ Y
w : ∀ (x : (forget C).obj X), f x = g x
⊢ ConcreteCategory.forget.map f = ConcreteCategory.forget.map g

Next tactic:
funext x
/-- In any concrete category, we can test equality of morphisms by pointwise evaluations.-/
@[ext low] -- Porting note: lowered priority
theorem ConcreteCategory.hom_ext {X Y : C} (f g : X ⟶ Y) (w : ∀ x : X, f x = g x) : f = g := by
  apply @Faithful.map_injective C _ (Type w) _ (forget C) _ X Y
  dsimp [forget]
  funext x
  

Proof state:
case a.h
C : Type u
inst✝¹ : Category.{v, u} C
inst✝ : ConcreteCategory C
X Y : C
f g : X ⟶ Y
w : ∀ (x : (forget C).obj X), f x = g x
x : ConcreteCategory.forget.obj X
⊢ ConcreteCategory.forget.map f x = ConcreteCategory.forget.map g x

Next tactic:
exact w x
theorem ConcreteCategory.bijective_of_isIso {X Y : C} (f : X ⟶ Y) [IsIso f] :
    Function.Bijective ((forget C).map f) := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : ConcreteCategory C
X Y : C
f : X ⟶ Y
inst✝ : IsIso f
⊢ Function.Bijective ((forget C).map f)

Next tactic:
rw [← isIso_iff_bijective]
theorem ConcreteCategory.bijective_of_isIso {X Y : C} (f : X ⟶ Y) [IsIso f] :
    Function.Bijective ((forget C).map f) := by
  rw [← isIso_iff_bijective]
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : ConcreteCategory C
X Y : C
f : X ⟶ Y
inst✝ : IsIso f
⊢ IsIso ((forget C).map f)

Next tactic:
infer_instance
instance forget₂_preservesMonomorphisms (C : Type u) (D : Type u')
    [Category.{v} C] [ConcreteCategory.{w} C] [Category.{v'} D] [ConcreteCategory.{w} D]
    [HasForget₂ C D] [(forget C).PreservesMonomorphisms] :
    (forget₂ C D).PreservesMonomorphisms :=
  have : (forget₂ C D ⋙ forget D).PreservesMonomorphisms := by
    

Proof state:
C : Type u
D : Type u'
inst✝⁵ : Category.{v, u} C
inst✝⁴ : ConcreteCategory C
inst✝³ : Category.{v', u'} D
inst✝² : ConcreteCategory D
inst✝¹ : HasForget₂ C D
inst✝ : Functor.PreservesMonomorphisms (forget C)
⊢ Functor.PreservesMonomorphisms (forget₂ C D ⋙ forget D)

Next tactic:
simp only [HasForget₂.forget_comp]
instance forget₂_preservesMonomorphisms (C : Type u) (D : Type u')
    [Category.{v} C] [ConcreteCategory.{w} C] [Category.{v'} D] [ConcreteCategory.{w} D]
    [HasForget₂ C D] [(forget C).PreservesMonomorphisms] :
    (forget₂ C D).PreservesMonomorphisms :=
  have : (forget₂ C D ⋙ forget D).PreservesMonomorphisms := by
    simp only [HasForget₂.forget_comp]
    

Proof state:
C : Type u
D : Type u'
inst✝⁵ : Category.{v, u} C
inst✝⁴ : ConcreteCategory C
inst✝³ : Category.{v', u'} D
inst✝² : ConcreteCategory D
inst✝¹ : HasForget₂ C D
inst✝ : Functor.PreservesMonomorphisms (forget C)
⊢ Functor.PreservesMonomorphisms (forget C)

Next tactic:
infer_instance
instance forget₂_preservesEpimorphisms (C : Type u) (D : Type u')
    [Category.{v} C] [ConcreteCategory.{w} C] [Category.{v'} D] [ConcreteCategory.{w} D]
    [HasForget₂ C D] [(forget C).PreservesEpimorphisms] :
    (forget₂ C D).PreservesEpimorphisms :=
  have : (forget₂ C D ⋙ forget D).PreservesEpimorphisms := by
    

Proof state:
C : Type u
D : Type u'
inst✝⁵ : Category.{v, u} C
inst✝⁴ : ConcreteCategory C
inst✝³ : Category.{v', u'} D
inst✝² : ConcreteCategory D
inst✝¹ : HasForget₂ C D
inst✝ : Functor.PreservesEpimorphisms (forget C)
⊢ Functor.PreservesEpimorphisms (forget₂ C D ⋙ forget D)

Next tactic:
simp only [HasForget₂.forget_comp]
instance forget₂_preservesEpimorphisms (C : Type u) (D : Type u')
    [Category.{v} C] [ConcreteCategory.{w} C] [Category.{v'} D] [ConcreteCategory.{w} D]
    [HasForget₂ C D] [(forget C).PreservesEpimorphisms] :
    (forget₂ C D).PreservesEpimorphisms :=
  have : (forget₂ C D ⋙ forget D).PreservesEpimorphisms := by
    simp only [HasForget₂.forget_comp]
    

Proof state:
C : Type u
D : Type u'
inst✝⁵ : Category.{v, u} C
inst✝⁴ : ConcreteCategory C
inst✝³ : Category.{v', u'} D
inst✝² : ConcreteCategory D
inst✝¹ : HasForget₂ C D
inst✝ : Functor.PreservesEpimorphisms (forget C)
⊢ Functor.PreservesEpimorphisms (forget C)

Next tactic:
infer_instance
/-- In order to construct a “partially forgetting” functor, we do not need to verify functor laws;
it suffices to ensure that compositions agree with `forget₂ C D ⋙ forget D = forget C`.
-/
def HasForget₂.mk' {C : Type u} {D : Type u'} [Category.{v} C] [ConcreteCategory.{w} C]
    [Category.{v'} D] [ConcreteCategory.{w} D]
    (obj : C → D) (h_obj : ∀ X, (forget D).obj (obj X) = (forget C).obj X)
    (map : ∀ {X Y}, (X ⟶ Y) → (obj X ⟶ obj Y))
    (h_map : ∀ {X Y} {f : X ⟶ Y}, HEq ((forget D).map (map f)) ((forget C).map f)) : HasForget₂ C D
    where
  forget₂ := Faithful.div _ _ _ @h_obj _ @h_map
  forget_comp := by 

Proof state:
C : Type u
D : Type u'
inst✝³ : Category.{v, u} C
inst✝² : ConcreteCategory C
inst✝¹ : Category.{v', u'} D
inst✝ : ConcreteCategory D
obj : C → D
h_obj : ∀ (X : C), (forget D).obj (obj X) = (forget C).obj X
map : {X Y : C} → (X ⟶ Y) → (obj X ⟶ obj Y)
h_map : ∀ {X Y : C} {f : X ⟶ Y}, HEq ((forget D).map (map f)) ((forget C).map f)
⊢ Faithful.div (forget C) (forget D) (fun X => obj X) h_obj (fun X Y f => map f) h_map ⋙ forget D = forget C

Next tactic:
apply Faithful.div_comp
@[simp]
theorem AbsoluteValue.map_units_int (abv : AbsoluteValue ℤ S) (x : ℤˣ) : abv x = 1 := by
  

Proof state:
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue ℤ S
x : ℤˣ
⊢ abv ↑x = 1

Next tactic:
rcases Int.units_eq_one_or x with (rfl | rfl)
@[simp]
theorem AbsoluteValue.map_units_int (abv : AbsoluteValue ℤ S) (x : ℤˣ) : abv x = 1 := by
  rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue ℤ S
⊢ abv ↑1 = 1

Next tactic:
simp
@[simp]
theorem AbsoluteValue.map_units_int (abv : AbsoluteValue ℤ S) (x : ℤˣ) : abv x = 1 := by
  rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue ℤ S
⊢ abv ↑(-1) = 1

Next tactic:
simp
@[simp]
theorem AbsoluteValue.map_units_int_cast [Nontrivial R] (abv : AbsoluteValue R S) (x : ℤˣ) :
    abv ((x : ℤ) : R) = 1 := by 

Proof state:
R : Type u_1
S : Type u_2
inst✝² : Ring R
inst✝¹ : LinearOrderedCommRing S
inst✝ : Nontrivial R
abv : AbsoluteValue R S
x : ℤˣ
⊢ abv ↑↑x = 1

Next tactic:
rcases Int.units_eq_one_or x with (rfl | rfl)
@[simp]
theorem AbsoluteValue.map_units_int_cast [Nontrivial R] (abv : AbsoluteValue R S) (x : ℤˣ) :
    abv ((x : ℤ) : R) = 1 := by rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
inst✝² : Ring R
inst✝¹ : LinearOrderedCommRing S
inst✝ : Nontrivial R
abv : AbsoluteValue R S
⊢ abv ↑↑1 = 1

Next tactic:
simp
@[simp]
theorem AbsoluteValue.map_units_int_cast [Nontrivial R] (abv : AbsoluteValue R S) (x : ℤˣ) :
    abv ((x : ℤ) : R) = 1 := by rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
inst✝² : Ring R
inst✝¹ : LinearOrderedCommRing S
inst✝ : Nontrivial R
abv : AbsoluteValue R S
⊢ abv ↑↑(-1) = 1

Next tactic:
simp
@[simp]
theorem AbsoluteValue.map_units_int_smul (abv : AbsoluteValue R S) (x : ℤˣ) (y : R) :
    abv (x • y) = abv y := by 

Proof state:
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue R S
x : ℤˣ
y : R
⊢ abv (x • y) = abv y

Next tactic:
rcases Int.units_eq_one_or x with (rfl | rfl)
@[simp]
theorem AbsoluteValue.map_units_int_smul (abv : AbsoluteValue R S) (x : ℤˣ) (y : R) :
    abv (x • y) = abv y := by rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inl
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue R S
y : R
⊢ abv (1 • y) = abv y

Next tactic:
simp
@[simp]
theorem AbsoluteValue.map_units_int_smul (abv : AbsoluteValue R S) (x : ℤˣ) (y : R) :
    abv (x • y) = abv y := by rcases Int.units_eq_one_or x with (rfl | rfl) <;> 

Proof state:
case inr
R : Type u_1
S : Type u_2
inst✝¹ : Ring R
inst✝ : LinearOrderedCommRing S
abv : AbsoluteValue R S
y : R
⊢ abv (-1 • y) = abv y

Next tactic:
simp