[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.Algebra.Subalgebra.Tower).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem restrictScalars_top : restrictScalars R (⊤ : Subalgebra S A) = ⊤
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.lmul_algebraMap (L46-L57)
theorem lmul_algebraMap (x : R) : Algebra.lmul R A (algebraMap R A x) = Algebra.lsmul R R A x :=
Eq.symm <| LinearMap.ext <| smul_def x

end Algebra

namespace IsScalarTower

section Semiring

variable [CommSemiring R] [CommSemiring S] [Semiring A]
variable [Algebra R S] [Algebra S A]
```

-- snippet 2
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.subalgebra (L58-L62)
instance subalgebra (S₀ : Subalgebra R S) : IsScalarTower S₀ S A :=
of_algebraMap_eq fun _ ↦ rfl

variable [Algebra R A] [IsScalarTower R S A]
```

-- snippet 3
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.subalgebra' (L63-L82)
instance subalgebra' (S₀ : Subalgebra R S) : IsScalarTower R S₀ A :=
@IsScalarTower.of_algebraMap_eq R S₀ A _ _ _ _ _ _ fun _ ↦
    (IsScalarTower.algebraMap_apply R S A _ :)

end Semiring

end IsScalarTower

namespace Subalgebra

open IsScalarTower

section Semiring

variable {S A B} [CommSemiring R] [CommSemiring S] [Semiring A] [Semiring B]
variable [Algebra R S] [Algebra S A] [Algebra R A] [Algebra S B] [Algebra R B]
variable [IsScalarTower R S A] [IsScalarTower R S B]

/-- Given a tower `A / ↥U / S / R` of algebras, where `U` is an `S`-subalgebra of `A`, reinterpret
`U` as an `R`-subalgebra of `A`. -/
```

-- snippet 4
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars (L83-L88)
def restrictScalars (U : Subalgebra S A) : Subalgebra R A :=
{ U with
    algebraMap_mem' := fun x ↦ by
      rw [IsScalarTower.algebraMap_apply R S A]
      exact U.algebraMap_mem _ }
```

-- snippet 5
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.coe_restrictScalars (L90-L92)
theorem coe_restrictScalars {U : Subalgebra S A} : (restrictScalars R U : Set A) = (U : Set A) :=
rfl
```

-- snippet 6
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars_toSubmodule (L100-L103)
theorem restrictScalars_toSubmodule {U : Subalgebra S A} :
    Subalgebra.toSubmodule (U.restrictScalars R) = U.toSubmodule.restrictScalars R :=
SetLike.coe_injective rfl
```

-- snippet 7
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.mem_restrictScalars (L105-L107)
theorem mem_restrictScalars {U : Subalgebra S A} {x : A} : x ∈ restrictScalars R U ↔ x ∈ U :=
Iff.rfl
```

-- snippet 8
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars_injective (L108-L114)
theorem restrictScalars_injective :
    Function.Injective (restrictScalars R : Subalgebra S A → Subalgebra R A) := fun U V H ↦
ext fun x ↦ by rw [← mem_restrictScalars R, H, mem_restrictScalars]

/-- Produces an `R`-algebra map from `U.restrictScalars R` given an `S`-algebra map from `U`.

This is a special case of `AlgHom.restrictScalars` that can be helpful in elaboration. -/
```

-- snippet 9
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.ofRestrictScalars (L116-L122)
def ofRestrictScalars (U : Subalgebra S A) (f : U →ₐ[S] B) : U.restrictScalars R →ₐ[R] B :=
f.restrictScalars R

end Semiring

section CommSemiring
```

-- snippet 10
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.range_isScalarTower_toAlgHom (L124-L140)
lemma range_isScalarTower_toAlgHom [CommSemiring R] [CommSemiring A]
    [Algebra R A] (S : Subalgebra R A) :
    LinearMap.range (IsScalarTower.toAlgHom R S A : S →ₗ[R] A) = Subalgebra.toSubmodule S := by
ext
  simp [algebraMap_eq]

end CommSemiring

end Subalgebra

namespace IsScalarTower

open Subalgebra

variable [CommSemiring R] [CommSemiring S] [CommSemiring A]
variable [Algebra R S] [Algebra S A] [Algebra R A] [IsScalarTower R S A]
```

-- snippet 11
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.adjoin_range_toAlgHom (L141-L148)
theorem adjoin_range_toAlgHom (t : Set A) :
    (Algebra.adjoin (toAlgHom R S A).range t).restrictScalars R =
      (Algebra.adjoin S t).restrictScalars R :=
Subalgebra.ext fun z ↦
    show z ∈ Subsemiring.closure (Set.range (algebraMap (toAlgHom R S A).range A) ∪ t : Set A) ↔
         z ∈ Subsemiring.closure (Set.range (algebraMap S A) ∪ t : Set A) by simp

end IsScalarTower
```

-- snippet 12
```lean
-- Mathlib.Algebra.Algebra.Basic.map_algebraMap_mul (L263-L266)
theorem map_algebraMap_mul (f : A →ₗ[R] B) (a : A) (r : R) :
    f (algebraMap R A r * a) = algebraMap R B r * f a := by
rw [← Algebra.smul_def, ← Algebra.smul_def, map_smul]
```

-- snippet 13
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubring_apply (L130-L137)
theorem algebraMap_ofSubring_apply {R : Type*} [CommRing R] (S : Subring R) (x : S) :
    algebraMap S R x = x :=
rfl

end SubsemiringAlgebra

/-- Explicit characterization of the submonoid map in the case of an algebra.
`S` is made explicit to help with type inference -/
```

-- snippet 14
```lean
-- Mathlib.Algebra.Algebra.Basic.mem_algebraMapSubmonoid_of_mem (L141-L144)
theorem mem_algebraMapSubmonoid_of_mem {S : Type*} [Semiring S] [Algebra R S] {M : Submonoid R}
    (x : M) : algebraMap R S x ∈ algebraMapSubmonoid S M :=
Set.mem_image_of_mem (algebraMap R S) x.2
```

-- snippet 15
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid (L138-L140)
def algebraMapSubmonoid (S : Type*) [Semiring S] [Algebra R S] (M : Submonoid R) : Submonoid S :=
M.map (algebraMap R S)
```

-- snippet 16
```lean
-- Mathlib.Algebra.Algebra.Basic.map_mul_algebraMap (L267-L280)
theorem map_mul_algebraMap (f : A →ₗ[R] B) (a : A) (r : R) :
    f (a * algebraMap R A r) = f a * algebraMap R B r := by
rw [← Algebra.commutes, ← Algebra.commutes, map_algebraMap_mul]

end LinearMap

section Nat

variable {R : Type*} [Semiring R]

-- Lower the priority so that `Algebra.id` is picked most of the time when working with
-- `ℕ`-algebras.
-- TODO: is this still needed?
/-- Semiring ⥤ ℕ-Alg -/
```

-- snippet 17
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid_self (L146-L148)
lemma algebraMapSubmonoid_self (M : Submonoid R) : Algebra.algebraMapSubmonoid R M = M :=
Submonoid.map_id M
```

-- snippet 18
```lean
-- Mathlib.Algebra.Algebra.Basic.mul_sub_algebraMap_pow_commutes (L163-L175)
theorem mul_sub_algebraMap_pow_commutes [Ring A] [Algebra R A] (x : A) (r : R) (n : ℕ) :
    x * (x - algebraMap R A r) ^ n = (x - algebraMap R A r) ^ n * x := by
induction n with
  | zero => simp
  | succ n ih =>
    rw [pow_succ', ← mul_assoc, mul_sub_algebraMap_commutes, mul_assoc, ih, ← mul_assoc]

end CommSemiring

section Ring

/-- A `Semiring` that is an `Algebra` over a commutative ring carries a natural `Ring` structure.
See note [reducible non-instances]. -/
```

-- snippet 19
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_end_apply (L222-L224)
theorem algebraMap_end_apply (a : R) (m : M) : algebraMap R (End S M) a m = a • m :=
rfl
```

-- snippet 20
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubsemiring_apply (L113-L116)
theorem algebraMap_ofSubsemiring_apply (S : C) (x : S) : algebraMap S R x = x :=
rfl

/-- Algebra over a subring. This builds upon `Subring.module`. -/
```

-- snippet 21
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_comp_natCast (L290-L303)
lemma algebraMap_comp_natCast (R A : Type*) [CommSemiring R] [Semiring A] [Algebra R A] :
    algebraMap R A ∘ Nat.cast = Nat.cast := by
ext; simp

end Nat

section Int

variable (R : Type*) [Ring R]

-- Lower the priority so that `Algebra.id` is picked most of the time when working with
-- `ℤ`-algebras.
-- TODO: is this still needed?
/-- Ring ⥤ ℤ-Alg -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_int_eq (L311-L315)
theorem algebraMap_int_eq : algebraMap ℤ R = Int.castRingHom R :=
rfl

variable {R}
```

-- snippet 23
```lean
-- Mathlib.Algebra.Algebra.Basic.End (L212-L215)
instance End.instAlgebra : Algebra R (Module.End S M) :=
Algebra.ofModule smul_mul_assoc fun r f g => (smul_comm r f g).symm

-- to prove this is a special case of the above
```

-- snippet 24
```lean
-- Mathlib.Algebra.Algebra.Basic.semiringToRing (L176-L183)
abbrev semiringToRing (R : Type*) [CommRing R] [Semiring A] [Algebra R A] : Ring A :=
{ __ := (inferInstance : Semiring A)
    __ := Module.addCommMonoidToAddCommGroup R
    intCast := fun z => algebraMap R A z
    intCast_ofNat := fun z => by simp only [Int.cast_natCast, map_natCast]
    intCast_negSucc := fun z => by simp }

/-- The `CommRing` structure on a `CommSemiring` induced by a ring morphism from a `CommRing`. -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.Algebra.Basic.nat_algebra_subsingleton (L286-L288)
instance nat_algebra_subsingleton : Subsingleton (Algebra ℕ R) :=
⟨fun P Q => by ext; simp⟩
```

-- snippet 26
```lean
-- Mathlib.Algebra.Algebra.Basic.coe_algebraMap_ofSubring (L125-L128)
theorem coe_algebraMap_ofSubring {R : Type*} [CommRing R] (S : Subring R) :
    (algebraMap S R : S → R) = Subtype.val :=
rfl
```

-- snippet 27
```lean
-- Mathlib.Algebra.Algebra.Basic.ofSubring (L117-L119)
instance ofSubring {R A : Type*} [CommRing R] [Ring A] [Algebra R A] (S : Subring R) :
    Algebra S A := inferInstance
```

-- snippet 28
```lean
-- Mathlib.Algebra.Algebra.Basic.ker_algebraMap_end (L226-L229)
theorem ker_algebraMap_end (K : Type u) (V : Type v) [Semifield K] [AddCommMonoid V] [Module K V]
    (a : K) (ha : a ≠ 0) : LinearMap.ker ((algebraMap K (End K V)) a) = ⊥ :=
LinearMap.ker_smul _ _ ha
```

-- snippet 29
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubsemiring (L106-L109)
theorem algebraMap_ofSubsemiring (S : Subsemiring R) :
    (algebraMap S R : S →+* R) = S.subtype :=
rfl
```

-- snippet 30
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_pUnit (L54-L60)
theorem algebraMap_pUnit (r : R) : algebraMap R PUnit r = PUnit.unit :=
rfl

end PUnit

section ULift
```

-- snippet 31
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid_powers (L150-L159)
lemma algebraMapSubmonoid_powers {S : Type*} [Semiring S] [Algebra R S] (r : R) :
    Algebra.algebraMapSubmonoid S (.powers r) = Submonoid.powers (algebraMap R S r) := by
simp [Algebra.algebraMapSubmonoid]

end Semiring

section CommSemiring

variable [CommSemiring R]
```

-- snippet 32
```lean
-- Mathlib.Algebra.Algebra.Basic.coe_algebraMap_ofSubsemiring (L110-L112)
theorem coe_algebraMap_ofSubsemiring (S : C) : (algebraMap S R : S → R) = Subtype.val :=
rfl
```

-- snippet 33
```lean
-- Mathlib.Algebra.Algebra.Basic.int_algebra_subsingleton (L316-L318)
instance int_algebra_subsingleton : Subsingleton (Algebra ℤ R) :=
⟨fun P Q => Algebra.algebra_ext P Q <| RingHom.congr_fun <| Subsingleton.elim _ _⟩
```

-- snippet 34
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_end_eq_smul_id (L218-L220)
theorem algebraMap_end_eq_smul_id (a : R) : algebraMap R (End S M) a = a • LinearMap.id :=
rfl
```

-- snippet 35
```lean
-- Mathlib.Algebra.Algebra.Basic.mul_sub_algebraMap_commutes (L160-L162)
theorem mul_sub_algebraMap_commutes [Ring A] [Algebra R A] (x : A) (r : R) :
    x * (x - algebraMap R A r) = (x - algebraMap R A r) * x := by rw [mul_sub, ← commutes, sub_mul]
```

-- snippet 36
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubring (L120-L123)
theorem algebraMap_ofSubring {R : Type*} [CommRing R] (S : Subring R) :
    (algebraMap S R : S →+* R) = S.subtype :=
rfl
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Algebra.Algebra.Subalgebra.Tower).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem restrictScalars_top : restrictScalars R (⊤ : Subalgebra S A) = ⊤
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.lmul_algebraMap (L46-L57)
theorem lmul_algebraMap (x : R) : Algebra.lmul R A (algebraMap R A x) = Algebra.lsmul R R A x :=
Eq.symm <| LinearMap.ext <| smul_def x

end Algebra

namespace IsScalarTower

section Semiring

variable [CommSemiring R] [CommSemiring S] [Semiring A]
variable [Algebra R S] [Algebra S A]
```

-- snippet 2
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.subalgebra (L58-L62)
instance subalgebra (S₀ : Subalgebra R S) : IsScalarTower S₀ S A :=
of_algebraMap_eq fun _ ↦ rfl

variable [Algebra R A] [IsScalarTower R S A]
```

-- snippet 3
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.subalgebra' (L63-L82)
instance subalgebra' (S₀ : Subalgebra R S) : IsScalarTower R S₀ A :=
@IsScalarTower.of_algebraMap_eq R S₀ A _ _ _ _ _ _ fun _ ↦
    (IsScalarTower.algebraMap_apply R S A _ :)

end Semiring

end IsScalarTower

namespace Subalgebra

open IsScalarTower

section Semiring

variable {S A B} [CommSemiring R] [CommSemiring S] [Semiring A] [Semiring B]
variable [Algebra R S] [Algebra S A] [Algebra R A] [Algebra S B] [Algebra R B]
variable [IsScalarTower R S A] [IsScalarTower R S B]

/-- Given a tower `A / ↥U / S / R` of algebras, where `U` is an `S`-subalgebra of `A`, reinterpret
`U` as an `R`-subalgebra of `A`. -/
```

-- snippet 4
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars (L83-L88)
def restrictScalars (U : Subalgebra S A) : Subalgebra R A :=
{ U with
    algebraMap_mem' := fun x ↦ by
      rw [IsScalarTower.algebraMap_apply R S A]
      exact U.algebraMap_mem _ }
```

-- snippet 5
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.coe_restrictScalars (L90-L92)
theorem coe_restrictScalars {U : Subalgebra S A} : (restrictScalars R U : Set A) = (U : Set A) :=
rfl
```

-- snippet 6
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars_toSubmodule (L100-L103)
theorem restrictScalars_toSubmodule {U : Subalgebra S A} :
    Subalgebra.toSubmodule (U.restrictScalars R) = U.toSubmodule.restrictScalars R :=
SetLike.coe_injective rfl
```

-- snippet 7
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.mem_restrictScalars (L105-L107)
theorem mem_restrictScalars {U : Subalgebra S A} {x : A} : x ∈ restrictScalars R U ↔ x ∈ U :=
Iff.rfl
```

-- snippet 8
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.restrictScalars_injective (L108-L114)
theorem restrictScalars_injective :
    Function.Injective (restrictScalars R : Subalgebra S A → Subalgebra R A) := fun U V H ↦
ext fun x ↦ by rw [← mem_restrictScalars R, H, mem_restrictScalars]

/-- Produces an `R`-algebra map from `U.restrictScalars R` given an `S`-algebra map from `U`.

This is a special case of `AlgHom.restrictScalars` that can be helpful in elaboration. -/
```

-- snippet 9
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.ofRestrictScalars (L116-L122)
def ofRestrictScalars (U : Subalgebra S A) (f : U →ₐ[S] B) : U.restrictScalars R →ₐ[R] B :=
f.restrictScalars R

end Semiring

section CommSemiring
```

-- snippet 10
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.range_isScalarTower_toAlgHom (L124-L140)
lemma range_isScalarTower_toAlgHom [CommSemiring R] [CommSemiring A]
    [Algebra R A] (S : Subalgebra R A) :
    LinearMap.range (IsScalarTower.toAlgHom R S A : S →ₗ[R] A) = Subalgebra.toSubmodule S := by
ext
  simp [algebraMap_eq]

end CommSemiring

end Subalgebra

namespace IsScalarTower

open Subalgebra

variable [CommSemiring R] [CommSemiring S] [CommSemiring A]
variable [Algebra R S] [Algebra S A] [Algebra R A] [IsScalarTower R S A]
```

-- snippet 11
```lean
-- Mathlib.Algebra.Algebra.Subalgebra.Tower.adjoin_range_toAlgHom (L141-L148)
theorem adjoin_range_toAlgHom (t : Set A) :
    (Algebra.adjoin (toAlgHom R S A).range t).restrictScalars R =
      (Algebra.adjoin S t).restrictScalars R :=
Subalgebra.ext fun z ↦
    show z ∈ Subsemiring.closure (Set.range (algebraMap (toAlgHom R S A).range A) ∪ t : Set A) ↔
         z ∈ Subsemiring.closure (Set.range (algebraMap S A) ∪ t : Set A) by simp

end IsScalarTower
```

-- snippet 12
```lean
-- Mathlib.Algebra.Algebra.Basic.map_algebraMap_mul (L263-L266)
theorem map_algebraMap_mul (f : A →ₗ[R] B) (a : A) (r : R) :
    f (algebraMap R A r * a) = algebraMap R B r * f a := by
rw [← Algebra.smul_def, ← Algebra.smul_def, map_smul]
```

-- snippet 13
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubring_apply (L130-L137)
theorem algebraMap_ofSubring_apply {R : Type*} [CommRing R] (S : Subring R) (x : S) :
    algebraMap S R x = x :=
rfl

end SubsemiringAlgebra

/-- Explicit characterization of the submonoid map in the case of an algebra.
`S` is made explicit to help with type inference -/
```

-- snippet 14
```lean
-- Mathlib.Algebra.Algebra.Basic.mem_algebraMapSubmonoid_of_mem (L141-L144)
theorem mem_algebraMapSubmonoid_of_mem {S : Type*} [Semiring S] [Algebra R S] {M : Submonoid R}
    (x : M) : algebraMap R S x ∈ algebraMapSubmonoid S M :=
Set.mem_image_of_mem (algebraMap R S) x.2
```

-- snippet 15
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid (L138-L140)
def algebraMapSubmonoid (S : Type*) [Semiring S] [Algebra R S] (M : Submonoid R) : Submonoid S :=
M.map (algebraMap R S)
```

-- snippet 16
```lean
-- Mathlib.Algebra.Algebra.Basic.map_mul_algebraMap (L267-L280)
theorem map_mul_algebraMap (f : A →ₗ[R] B) (a : A) (r : R) :
    f (a * algebraMap R A r) = f a * algebraMap R B r := by
rw [← Algebra.commutes, ← Algebra.commutes, map_algebraMap_mul]

end LinearMap

section Nat

variable {R : Type*} [Semiring R]

-- Lower the priority so that `Algebra.id` is picked most of the time when working with
-- `ℕ`-algebras.
-- TODO: is this still needed?
/-- Semiring ⥤ ℕ-Alg -/
```

-- snippet 17
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid_self (L146-L148)
lemma algebraMapSubmonoid_self (M : Submonoid R) : Algebra.algebraMapSubmonoid R M = M :=
Submonoid.map_id M
```

-- snippet 18
```lean
-- Mathlib.Algebra.Algebra.Basic.mul_sub_algebraMap_pow_commutes (L163-L175)
theorem mul_sub_algebraMap_pow_commutes [Ring A] [Algebra R A] (x : A) (r : R) (n : ℕ) :
    x * (x - algebraMap R A r) ^ n = (x - algebraMap R A r) ^ n * x := by
induction n with
  | zero => simp
  | succ n ih =>
    rw [pow_succ', ← mul_assoc, mul_sub_algebraMap_commutes, mul_assoc, ih, ← mul_assoc]

end CommSemiring

section Ring

/-- A `Semiring` that is an `Algebra` over a commutative ring carries a natural `Ring` structure.
See note [reducible non-instances]. -/
```

-- snippet 19
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_end_apply (L222-L224)
theorem algebraMap_end_apply (a : R) (m : M) : algebraMap R (End S M) a m = a • m :=
rfl
```

-- snippet 20
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubsemiring_apply (L113-L116)
theorem algebraMap_ofSubsemiring_apply (S : C) (x : S) : algebraMap S R x = x :=
rfl

/-- Algebra over a subring. This builds upon `Subring.module`. -/
```

-- snippet 21
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_comp_natCast (L290-L303)
lemma algebraMap_comp_natCast (R A : Type*) [CommSemiring R] [Semiring A] [Algebra R A] :
    algebraMap R A ∘ Nat.cast = Nat.cast := by
ext; simp

end Nat

section Int

variable (R : Type*) [Ring R]

-- Lower the priority so that `Algebra.id` is picked most of the time when working with
-- `ℤ`-algebras.
-- TODO: is this still needed?
/-- Ring ⥤ ℤ-Alg -/
```

-- snippet 22
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_int_eq (L311-L315)
theorem algebraMap_int_eq : algebraMap ℤ R = Int.castRingHom R :=
rfl

variable {R}
```

-- snippet 23
```lean
-- Mathlib.Algebra.Algebra.Basic.End (L212-L215)
instance End.instAlgebra : Algebra R (Module.End S M) :=
Algebra.ofModule smul_mul_assoc fun r f g => (smul_comm r f g).symm

-- to prove this is a special case of the above
```

-- snippet 24
```lean
-- Mathlib.Algebra.Algebra.Basic.semiringToRing (L176-L183)
abbrev semiringToRing (R : Type*) [CommRing R] [Semiring A] [Algebra R A] : Ring A :=
{ __ := (inferInstance : Semiring A)
    __ := Module.addCommMonoidToAddCommGroup R
    intCast := fun z => algebraMap R A z
    intCast_ofNat := fun z => by simp only [Int.cast_natCast, map_natCast]
    intCast_negSucc := fun z => by simp }

/-- The `CommRing` structure on a `CommSemiring` induced by a ring morphism from a `CommRing`. -/
```

-- snippet 25
```lean
-- Mathlib.Algebra.Algebra.Basic.nat_algebra_subsingleton (L286-L288)
instance nat_algebra_subsingleton : Subsingleton (Algebra ℕ R) :=
⟨fun P Q => by ext; simp⟩
```

-- snippet 26
```lean
-- Mathlib.Algebra.Algebra.Basic.coe_algebraMap_ofSubring (L125-L128)
theorem coe_algebraMap_ofSubring {R : Type*} [CommRing R] (S : Subring R) :
    (algebraMap S R : S → R) = Subtype.val :=
rfl
```

-- snippet 27
```lean
-- Mathlib.Algebra.Algebra.Basic.ofSubring (L117-L119)
instance ofSubring {R A : Type*} [CommRing R] [Ring A] [Algebra R A] (S : Subring R) :
    Algebra S A := inferInstance
```

-- snippet 28
```lean
-- Mathlib.Algebra.Algebra.Basic.ker_algebraMap_end (L226-L229)
theorem ker_algebraMap_end (K : Type u) (V : Type v) [Semifield K] [AddCommMonoid V] [Module K V]
    (a : K) (ha : a ≠ 0) : LinearMap.ker ((algebraMap K (End K V)) a) = ⊥ :=
LinearMap.ker_smul _ _ ha
```

-- snippet 29
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubsemiring (L106-L109)
theorem algebraMap_ofSubsemiring (S : Subsemiring R) :
    (algebraMap S R : S →+* R) = S.subtype :=
rfl
```

-- snippet 30
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_pUnit (L54-L60)
theorem algebraMap_pUnit (r : R) : algebraMap R PUnit r = PUnit.unit :=
rfl

end PUnit

section ULift
```

-- snippet 31
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMapSubmonoid_powers (L150-L159)
lemma algebraMapSubmonoid_powers {S : Type*} [Semiring S] [Algebra R S] (r : R) :
    Algebra.algebraMapSubmonoid S (.powers r) = Submonoid.powers (algebraMap R S r) := by
simp [Algebra.algebraMapSubmonoid]

end Semiring

section CommSemiring

variable [CommSemiring R]
```

-- snippet 32
```lean
-- Mathlib.Algebra.Algebra.Basic.coe_algebraMap_ofSubsemiring (L110-L112)
theorem coe_algebraMap_ofSubsemiring (S : C) : (algebraMap S R : S → R) = Subtype.val :=
rfl
```

-- snippet 33
```lean
-- Mathlib.Algebra.Algebra.Basic.int_algebra_subsingleton (L316-L318)
instance int_algebra_subsingleton : Subsingleton (Algebra ℤ R) :=
⟨fun P Q => Algebra.algebra_ext P Q <| RingHom.congr_fun <| Subsingleton.elim _ _⟩
```

-- snippet 34
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_end_eq_smul_id (L218-L220)
theorem algebraMap_end_eq_smul_id (a : R) : algebraMap R (End S M) a = a • LinearMap.id :=
rfl
```

-- snippet 35
```lean
-- Mathlib.Algebra.Algebra.Basic.mul_sub_algebraMap_commutes (L160-L162)
theorem mul_sub_algebraMap_commutes [Ring A] [Algebra R A] (x : A) (r : R) :
    x * (x - algebraMap R A r) = (x - algebraMap R A r) * x := by rw [mul_sub, ← commutes, sub_mul]
```

-- snippet 36
```lean
-- Mathlib.Algebra.Algebra.Basic.algebraMap_ofSubring (L120-L123)
theorem algebraMap_ofSubring {R : Type*} [CommRing R] (S : Subring R) :
    (algebraMap S R : S →+* R) = S.subtype :=
rfl
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Order.UpperLower.Basic).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem isLowerSet_setOf : IsLowerSet { a | p a } ↔ Antitone p
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_empty (L39-L40)
theorem isUpperSet_empty : IsUpperSet (∅ : Set α) := fun _ _ _ => id
```

-- snippet 2
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_univ (L42-L43)
theorem isUpperSet_univ : IsUpperSet (univ : Set α) := fun _ _ _ => id
```

-- snippet 3
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L45-L46)
theorem IsUpperSet.compl (hs : IsUpperSet s) : IsLowerSet sᶜ := fun _a _b h hb ha => hb <| hs h ha
```

-- snippet 4
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_compl (L48-L52)
theorem isUpperSet_compl : IsUpperSet sᶜ ↔ IsLowerSet s :=
⟨fun h => by
    convert h.compl
    rw [compl_compl], IsLowerSet.compl⟩
```

-- snippet 5
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L54-L56)
theorem IsUpperSet.union (hs : IsUpperSet s) (ht : IsUpperSet t) : IsUpperSet (s ∪ t) :=
fun _ _ h => Or.imp (hs h) (ht h)
```

-- snippet 6
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L58-L60)
theorem IsUpperSet.inter (hs : IsUpperSet s) (ht : IsUpperSet t) : IsUpperSet (s ∩ t) :=
fun _ _ h => And.imp (hs h) (ht h)
```

-- snippet 7
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_sUnion (L62-L64)
theorem isUpperSet_sUnion {S : Set (Set α)} (hf : ∀ s ∈ S, IsUpperSet s) : IsUpperSet (⋃₀ S) :=
fun _ _ h => Exists.imp fun _ hs => ⟨hs.1, hf _ hs.1 h hs.2⟩
```

-- snippet 8
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iUnion (L66-L68)
theorem isUpperSet_iUnion {f : ι → Set α} (hf : ∀ i, IsUpperSet (f i)) : IsUpperSet (⋃ i, f i) :=
isUpperSet_sUnion <| forall_mem_range.2 hf
```

-- snippet 9
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iUnion₂ (L70-L73)
theorem isUpperSet_iUnion₂ {f : ∀ i, κ i → Set α} (hf : ∀ i j, IsUpperSet (f i j)) :
    IsUpperSet (⋃ (i) (j), f i j) :=
isUpperSet_iUnion fun i => isUpperSet_iUnion <| hf i
```

-- snippet 10
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_sInter (L75-L77)
theorem isUpperSet_sInter {S : Set (Set α)} (hf : ∀ s ∈ S, IsUpperSet s) : IsUpperSet (⋂₀ S) :=
fun _ _ h => forall₂_imp fun s hs => hf s hs h
```

-- snippet 11
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iInter (L79-L81)
theorem isUpperSet_iInter {f : ι → Set α} (hf : ∀ i, IsUpperSet (f i)) : IsUpperSet (⋂ i, f i) :=
isUpperSet_sInter <| forall_mem_range.2 hf
```

-- snippet 12
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iInter₂ (L83-L86)
theorem isUpperSet_iInter₂ {f : ∀ i, κ i → Set α} (hf : ∀ i j, IsUpperSet (f i j)) :
    IsUpperSet (⋂ (i) (j), f i j) :=
isUpperSet_iInter fun i => isUpperSet_iInter <| hf i
```

-- snippet 13
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_preimage_ofDual_iff (L88-L90)
theorem isUpperSet_preimage_ofDual_iff : IsUpperSet (ofDual ⁻¹' s) ↔ IsLowerSet s :=
Iff.rfl
```

-- snippet 14
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_preimage_toDual_iff (L92-L94)
theorem isUpperSet_preimage_toDual_iff {s : Set αᵒᵈ} : IsUpperSet (toDual ⁻¹' s) ↔ IsLowerSet s :=
Iff.rfl
```

-- snippet 15
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L99-L101)
lemma IsUpperSet.isLowerSet_preimage_coe (hs : IsUpperSet s) :
    IsLowerSet ((↑) ⁻¹' t : Set s) ↔ ∀ b ∈ s, ∀ c ∈ t, b ≤ c → b ∈ t := by aesop
```

-- snippet 16
```lean
-- Mathlib.Order.UpperLower.Closure.subset_upperClosure (L54-L55)
theorem subset_upperClosure : s ⊆ upperClosure s := fun x hx => ⟨x, hx, le_rfl⟩
```

-- snippet 17
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_univ (L128-L130)
theorem upperClosure_univ : upperClosure (univ : Set α) = ⊥ :=
bot_unique subset_upperClosure
```

-- snippet 18
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_union (L131-L133)
theorem upperClosure_union (s t : Set α) : upperClosure (s ∪ t) = upperClosure s ⊓ upperClosure t :=
(@gc_upperClosure_coe α _).l_sup
```

-- snippet 19
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_eq_top_iff (L115-L117)
theorem upperClosure_eq_top_iff : upperClosure s = ⊤ ↔ s = ∅ := by
rw [eq_top_iff, le_upperClosure]; simp
```

-- snippet 20
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_sUnion (L146-L148)
theorem upperClosure_sUnion (S : Set (Set α)) : upperClosure (⋃₀ S) = ⨅ s ∈ S, upperClosure s := by
simp_rw [sUnion_eq_biUnion, upperClosure_iUnion]
```

-- snippet 21
```lean
-- Mathlib.Order.UpperLower.Closure.mem_upperClosure (L40-L43)
theorem mem_upperClosure : x ∈ upperClosure s ↔ ∃ a ∈ s, a ≤ x :=
Iff.rfl

-- We do not tag this as `simp` to respect the abstraction.
```

-- snippet 22
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_singleton (L123-L126)
theorem upperClosure_singleton (a : α) : upperClosure ({a} : Set α) = UpperSet.Ici a := by
ext
  simp
```

-- snippet 23
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_mono (L111-L113)
theorem lowerClosure_mono : Monotone (lowerClosure : Set α → LowerSet α) :=
gc_lowerClosure_coe.monotone_l
```

-- snippet 24
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_anti (L108-L110)
theorem upperClosure_anti : Antitone (upperClosure : Set α → UpperSet α) :=
gc_upperClosure_coe.monotone_l
```

-- snippet 25
```lean
-- Mathlib.Order.UpperLower.Closure.instDecidablePredMemUpperClosure (L50-L52)
instance instDecidablePredMemUpperClosure [DecidablePred (∃ a ∈ s, a ≤ ·)] :
    DecidablePred (· ∈ upperClosure s) := ‹DecidablePred _›
```

-- snippet 26
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_empty (L119-L121)
theorem upperClosure_empty : upperClosure (∅ : Set α) = ⊤ :=
upperClosure_eq_top_iff.mpr rfl
```

-- snippet 27
```lean
-- Mathlib.Order.UpperLower.Closure.giLowerClosureCoe (L102-L107)
def giLowerClosureCoe : GaloisInsertion (lowerClosure : Set α → LowerSet α) (↑) where
  choice s hs := ⟨s, fun a _b hba ha => hs ⟨a, ha, hba⟩⟩
gc := gc_lowerClosure_coe
  le_l_u _ := subset_lowerClosure
  choice_eq _s hs := SetLike.coe_injective <| subset_lowerClosure.antisymm hs
```

-- snippet 28
```lean
-- Mathlib.Order.UpperLower.Closure.gc_lowerClosure_coe (L90-L93)
theorem gc_lowerClosure_coe :
    GaloisConnection (lowerClosure : Set α → LowerSet α) (↑) := fun _s _t ↦ lowerClosure_le
/-- `upperClosure` forms a reversed Galois insertion with the coercion from upper sets to sets. -/
```

-- snippet 29
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure (L36-L38)
def upperClosure (s : Set α) : UpperSet α :=
⟨{ x | ∃ a ∈ s, a ≤ x }, fun _ _ hle h => h.imp fun _x hx => ⟨hx.1, hx.2.trans hle⟩⟩
```

-- snippet 30
```lean
-- Mathlib.Order.UpperLower.Closure.UpperSet (L77-L80)
theorem UpperSet.iInf_Ici (s : Set α) : ⨅ a ∈ s, UpperSet.Ici a = upperClosure s := by
ext
  simp
```

-- snippet 31
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_min (L57-L59)
theorem upperClosure_min (h : s ⊆ t) (ht : IsUpperSet t) : ↑(upperClosure s) ⊆ t :=
fun _a ⟨_b, hb, hba⟩ => ht hba <| h hb
```

-- snippet 32
```lean
-- Mathlib.Order.UpperLower.Closure.Set (L149-L153)
theorem Set.OrdConnected.upperClosure_inter_lowerClosure (h : s.OrdConnected) :
    ↑(upperClosure s) ∩ ↑(lowerClosure s) = s :=
(subset_inter subset_upperClosure subset_lowerClosure).antisymm'
    fun _a ⟨⟨_b, hb, hba⟩, _c, hc, hac⟩ => h.out hb hc ⟨hba, hac⟩
```

-- snippet 33
```lean
-- Mathlib.Order.UpperLower.Closure.gc_upperClosure_coe (L86-L89)
theorem gc_upperClosure_coe :
    GaloisConnection (toDual ∘ upperClosure : Set α → (UpperSet α)ᵒᵈ) ((↑) ∘ ofDual) :=
fun _s _t ↦ le_upperClosure
```

-- snippet 34
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_iUnion (L138-L140)
theorem upperClosure_iUnion (f : ι → Set α) : upperClosure (⋃ i, f i) = ⨅ i, upperClosure (f i) :=
(@gc_upperClosure_coe α _).l_iSup
```

-- snippet 35
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_union (L135-L137)
theorem lowerClosure_union (s t : Set α) : lowerClosure (s ∪ t) = lowerClosure s ⊔ lowerClosure t :=
(@gc_lowerClosure_coe α _).l_sup
```

-- snippet 36
```lean
-- Mathlib.Order.UpperLower.Closure.giUpperClosureCoe (L94-L101)
def giUpperClosureCoe :
    GaloisInsertion (toDual ∘ upperClosure : Set α → (UpperSet α)ᵒᵈ) ((↑) ∘ ofDual) where
  choice s hs := toDual (⟨s, fun a _b hab ha => hs ⟨a, ha, hab⟩⟩ : UpperSet α)
gc := gc_upperClosure_coe
  le_l_u _ := subset_upperClosure
  choice_eq _s hs := ofDual.injective <| SetLike.coe_injective <| subset_upperClosure.antisymm hs

/-- `lowerClosure` forms a Galois insertion with the coercion from lower sets to sets. -/
```

-- snippet 37
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_iUnion (L142-L144)
theorem lowerClosure_iUnion (f : ι → Set α) : lowerClosure (⋃ i, f i) = ⨆ i, lowerClosure (f i) :=
(@gc_lowerClosure_coe α _).l_iSup
```

-- snippet 38
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_le (L82-L85)
lemma lowerClosure_le {t : LowerSet α} : lowerClosure s ≤ t ↔ s ⊆ t :=
⟨fun h ↦ subset_lowerClosure.trans <| LowerSet.coe_subset_coe.2 h,
    fun h ↦ lowerClosure_min h t.lower⟩
```

-- snippet 39
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_image (L69-L75)
theorem upperClosure_image (f : α ≃o β) :
    upperClosure (f '' s) = UpperSet.map f (upperClosure s) := by
rw [← f.symm_symm, ← UpperSet.symm_map, f.symm_symm]
  ext
  simp only [SetLike.mem_coe]
  simp [f.le_symm_apply]
```

-- snippet 40
```lean
-- Mathlib.Order.UpperLower.Closure.coe_upperClosure (L45-L48)
theorem coe_upperClosure (s : Set α) : ↑(upperClosure s) = ⋃ a ∈ s, Ici a := by
ext
  simp
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Order.UpperLower.Basic).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem isLowerSet_setOf : IsLowerSet { a | p a } ↔ Antitone p
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_empty (L39-L40)
theorem isUpperSet_empty : IsUpperSet (∅ : Set α) := fun _ _ _ => id
```

-- snippet 2
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_univ (L42-L43)
theorem isUpperSet_univ : IsUpperSet (univ : Set α) := fun _ _ _ => id
```

-- snippet 3
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L45-L46)
theorem IsUpperSet.compl (hs : IsUpperSet s) : IsLowerSet sᶜ := fun _a _b h hb ha => hb <| hs h ha
```

-- snippet 4
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_compl (L48-L52)
theorem isUpperSet_compl : IsUpperSet sᶜ ↔ IsLowerSet s :=
⟨fun h => by
    convert h.compl
    rw [compl_compl], IsLowerSet.compl⟩
```

-- snippet 5
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L54-L56)
theorem IsUpperSet.union (hs : IsUpperSet s) (ht : IsUpperSet t) : IsUpperSet (s ∪ t) :=
fun _ _ h => Or.imp (hs h) (ht h)
```

-- snippet 6
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L58-L60)
theorem IsUpperSet.inter (hs : IsUpperSet s) (ht : IsUpperSet t) : IsUpperSet (s ∩ t) :=
fun _ _ h => And.imp (hs h) (ht h)
```

-- snippet 7
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_sUnion (L62-L64)
theorem isUpperSet_sUnion {S : Set (Set α)} (hf : ∀ s ∈ S, IsUpperSet s) : IsUpperSet (⋃₀ S) :=
fun _ _ h => Exists.imp fun _ hs => ⟨hs.1, hf _ hs.1 h hs.2⟩
```

-- snippet 8
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iUnion (L66-L68)
theorem isUpperSet_iUnion {f : ι → Set α} (hf : ∀ i, IsUpperSet (f i)) : IsUpperSet (⋃ i, f i) :=
isUpperSet_sUnion <| forall_mem_range.2 hf
```

-- snippet 9
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iUnion₂ (L70-L73)
theorem isUpperSet_iUnion₂ {f : ∀ i, κ i → Set α} (hf : ∀ i j, IsUpperSet (f i j)) :
    IsUpperSet (⋃ (i) (j), f i j) :=
isUpperSet_iUnion fun i => isUpperSet_iUnion <| hf i
```

-- snippet 10
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_sInter (L75-L77)
theorem isUpperSet_sInter {S : Set (Set α)} (hf : ∀ s ∈ S, IsUpperSet s) : IsUpperSet (⋂₀ S) :=
fun _ _ h => forall₂_imp fun s hs => hf s hs h
```

-- snippet 11
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iInter (L79-L81)
theorem isUpperSet_iInter {f : ι → Set α} (hf : ∀ i, IsUpperSet (f i)) : IsUpperSet (⋂ i, f i) :=
isUpperSet_sInter <| forall_mem_range.2 hf
```

-- snippet 12
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_iInter₂ (L83-L86)
theorem isUpperSet_iInter₂ {f : ∀ i, κ i → Set α} (hf : ∀ i j, IsUpperSet (f i j)) :
    IsUpperSet (⋂ (i) (j), f i j) :=
isUpperSet_iInter fun i => isUpperSet_iInter <| hf i
```

-- snippet 13
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_preimage_ofDual_iff (L88-L90)
theorem isUpperSet_preimage_ofDual_iff : IsUpperSet (ofDual ⁻¹' s) ↔ IsLowerSet s :=
Iff.rfl
```

-- snippet 14
```lean
-- Mathlib.Order.UpperLower.Basic.isUpperSet_preimage_toDual_iff (L92-L94)
theorem isUpperSet_preimage_toDual_iff {s : Set αᵒᵈ} : IsUpperSet (toDual ⁻¹' s) ↔ IsLowerSet s :=
Iff.rfl
```

-- snippet 15
```lean
-- Mathlib.Order.UpperLower.Basic.IsUpperSet (L99-L101)
lemma IsUpperSet.isLowerSet_preimage_coe (hs : IsUpperSet s) :
    IsLowerSet ((↑) ⁻¹' t : Set s) ↔ ∀ b ∈ s, ∀ c ∈ t, b ≤ c → b ∈ t := by aesop
```

-- snippet 16
```lean
-- Mathlib.Order.UpperLower.Closure.subset_upperClosure (L54-L55)
theorem subset_upperClosure : s ⊆ upperClosure s := fun x hx => ⟨x, hx, le_rfl⟩
```

-- snippet 17
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_univ (L128-L130)
theorem upperClosure_univ : upperClosure (univ : Set α) = ⊥ :=
bot_unique subset_upperClosure
```

-- snippet 18
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_union (L131-L133)
theorem upperClosure_union (s t : Set α) : upperClosure (s ∪ t) = upperClosure s ⊓ upperClosure t :=
(@gc_upperClosure_coe α _).l_sup
```

-- snippet 19
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_eq_top_iff (L115-L117)
theorem upperClosure_eq_top_iff : upperClosure s = ⊤ ↔ s = ∅ := by
rw [eq_top_iff, le_upperClosure]; simp
```

-- snippet 20
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_sUnion (L146-L148)
theorem upperClosure_sUnion (S : Set (Set α)) : upperClosure (⋃₀ S) = ⨅ s ∈ S, upperClosure s := by
simp_rw [sUnion_eq_biUnion, upperClosure_iUnion]
```

-- snippet 21
```lean
-- Mathlib.Order.UpperLower.Closure.mem_upperClosure (L40-L43)
theorem mem_upperClosure : x ∈ upperClosure s ↔ ∃ a ∈ s, a ≤ x :=
Iff.rfl

-- We do not tag this as `simp` to respect the abstraction.
```

-- snippet 22
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_singleton (L123-L126)
theorem upperClosure_singleton (a : α) : upperClosure ({a} : Set α) = UpperSet.Ici a := by
ext
  simp
```

-- snippet 23
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_mono (L111-L113)
theorem lowerClosure_mono : Monotone (lowerClosure : Set α → LowerSet α) :=
gc_lowerClosure_coe.monotone_l
```

-- snippet 24
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_anti (L108-L110)
theorem upperClosure_anti : Antitone (upperClosure : Set α → UpperSet α) :=
gc_upperClosure_coe.monotone_l
```

-- snippet 25
```lean
-- Mathlib.Order.UpperLower.Closure.instDecidablePredMemUpperClosure (L50-L52)
instance instDecidablePredMemUpperClosure [DecidablePred (∃ a ∈ s, a ≤ ·)] :
    DecidablePred (· ∈ upperClosure s) := ‹DecidablePred _›
```

-- snippet 26
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_empty (L119-L121)
theorem upperClosure_empty : upperClosure (∅ : Set α) = ⊤ :=
upperClosure_eq_top_iff.mpr rfl
```

-- snippet 27
```lean
-- Mathlib.Order.UpperLower.Closure.giLowerClosureCoe (L102-L107)
def giLowerClosureCoe : GaloisInsertion (lowerClosure : Set α → LowerSet α) (↑) where
  choice s hs := ⟨s, fun a _b hba ha => hs ⟨a, ha, hba⟩⟩
gc := gc_lowerClosure_coe
  le_l_u _ := subset_lowerClosure
  choice_eq _s hs := SetLike.coe_injective <| subset_lowerClosure.antisymm hs
```

-- snippet 28
```lean
-- Mathlib.Order.UpperLower.Closure.gc_lowerClosure_coe (L90-L93)
theorem gc_lowerClosure_coe :
    GaloisConnection (lowerClosure : Set α → LowerSet α) (↑) := fun _s _t ↦ lowerClosure_le
/-- `upperClosure` forms a reversed Galois insertion with the coercion from upper sets to sets. -/
```

-- snippet 29
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure (L36-L38)
def upperClosure (s : Set α) : UpperSet α :=
⟨{ x | ∃ a ∈ s, a ≤ x }, fun _ _ hle h => h.imp fun _x hx => ⟨hx.1, hx.2.trans hle⟩⟩
```

-- snippet 30
```lean
-- Mathlib.Order.UpperLower.Closure.UpperSet (L77-L80)
theorem UpperSet.iInf_Ici (s : Set α) : ⨅ a ∈ s, UpperSet.Ici a = upperClosure s := by
ext
  simp
```

-- snippet 31
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_min (L57-L59)
theorem upperClosure_min (h : s ⊆ t) (ht : IsUpperSet t) : ↑(upperClosure s) ⊆ t :=
fun _a ⟨_b, hb, hba⟩ => ht hba <| h hb
```

-- snippet 32
```lean
-- Mathlib.Order.UpperLower.Closure.Set (L149-L153)
theorem Set.OrdConnected.upperClosure_inter_lowerClosure (h : s.OrdConnected) :
    ↑(upperClosure s) ∩ ↑(lowerClosure s) = s :=
(subset_inter subset_upperClosure subset_lowerClosure).antisymm'
    fun _a ⟨⟨_b, hb, hba⟩, _c, hc, hac⟩ => h.out hb hc ⟨hba, hac⟩
```

-- snippet 33
```lean
-- Mathlib.Order.UpperLower.Closure.gc_upperClosure_coe (L86-L89)
theorem gc_upperClosure_coe :
    GaloisConnection (toDual ∘ upperClosure : Set α → (UpperSet α)ᵒᵈ) ((↑) ∘ ofDual) :=
fun _s _t ↦ le_upperClosure
```

-- snippet 34
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_iUnion (L138-L140)
theorem upperClosure_iUnion (f : ι → Set α) : upperClosure (⋃ i, f i) = ⨅ i, upperClosure (f i) :=
(@gc_upperClosure_coe α _).l_iSup
```

-- snippet 35
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_union (L135-L137)
theorem lowerClosure_union (s t : Set α) : lowerClosure (s ∪ t) = lowerClosure s ⊔ lowerClosure t :=
(@gc_lowerClosure_coe α _).l_sup
```

-- snippet 36
```lean
-- Mathlib.Order.UpperLower.Closure.giUpperClosureCoe (L94-L101)
def giUpperClosureCoe :
    GaloisInsertion (toDual ∘ upperClosure : Set α → (UpperSet α)ᵒᵈ) ((↑) ∘ ofDual) where
  choice s hs := toDual (⟨s, fun a _b hab ha => hs ⟨a, ha, hab⟩⟩ : UpperSet α)
gc := gc_upperClosure_coe
  le_l_u _ := subset_upperClosure
  choice_eq _s hs := ofDual.injective <| SetLike.coe_injective <| subset_upperClosure.antisymm hs

/-- `lowerClosure` forms a Galois insertion with the coercion from lower sets to sets. -/
```

-- snippet 37
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_iUnion (L142-L144)
theorem lowerClosure_iUnion (f : ι → Set α) : lowerClosure (⋃ i, f i) = ⨆ i, lowerClosure (f i) :=
(@gc_lowerClosure_coe α _).l_iSup
```

-- snippet 38
```lean
-- Mathlib.Order.UpperLower.Closure.lowerClosure_le (L82-L85)
lemma lowerClosure_le {t : LowerSet α} : lowerClosure s ≤ t ↔ s ⊆ t :=
⟨fun h ↦ subset_lowerClosure.trans <| LowerSet.coe_subset_coe.2 h,
    fun h ↦ lowerClosure_min h t.lower⟩
```

-- snippet 39
```lean
-- Mathlib.Order.UpperLower.Closure.upperClosure_image (L69-L75)
theorem upperClosure_image (f : α ≃o β) :
    upperClosure (f '' s) = UpperSet.map f (upperClosure s) := by
rw [← f.symm_symm, ← UpperSet.symm_map, f.symm_symm]
  ext
  simp only [SetLike.mem_coe]
  simp [f.le_symm_apply]
```

-- snippet 40
```lean
-- Mathlib.Order.UpperLower.Closure.coe_upperClosure (L45-L48)
theorem coe_upperClosure (s : Set α) : ↑(upperClosure s) = ⋃ a ∈ s, Ici a := by
ext
  simp
```
[/INST]

mistral-common:Tekken v15 (Mistral chat template, [INST]/[SYSTEM_PROMPT])


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Topology.Separation.Basic).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem IsCompact.closure_of_subset {s K : Set X} (hK : IsCompact K) (h : s ⊆ K) :
    IsCompact (closure s)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_inseparable (L81-L84)
theorem t0Space_iff_inseparable (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ ∀ x y : X, Inseparable x y → x = y :=
⟨fun ⟨h⟩ => h, fun h => ⟨h⟩⟩
```

-- snippet 2
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_not_inseparable (L85-L88)
theorem t0Space_iff_not_inseparable (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Pairwise fun x y : X => ¬Inseparable x y := by
simp only [t0Space_iff_inseparable, Ne, not_imp_not, Pairwise]
```

-- snippet 3
```lean
-- Mathlib.Topology.Separation.Basic.Inseparable (L89-L101)
theorem Inseparable.eq [T0Space X] {x y : X} (h : Inseparable x y) : x = y :=
T0Space.t0 h

/-- A topology inducing map from a T₀ space is injective. -/
protected theorem Topology.IsInducing.injective [TopologicalSpace Y] [T0Space X] {f : X → Y}
    (hf : IsInducing f) : Injective f := fun _ _ h =>
  (hf.inseparable_iff.1 <| .of_eq h).eq

/-- A topology inducing map from a T₀ space is a topological embedding. -/
protected theorem Topology.IsInducing.isEmbedding [TopologicalSpace Y] [T0Space X] {f : X → Y}
    (hf : IsInducing f) : IsEmbedding f :=
  ⟨hf, hf.injective⟩
```

-- snippet 4
```lean
-- Mathlib.Topology.Separation.Basic.isEmbedding_iff_isInducing (L102-L105)
lemma isEmbedding_iff_isInducing [TopologicalSpace Y] [T0Space X] {f : X → Y} :
    IsEmbedding f ↔ IsInducing f :=
⟨IsEmbedding.isInducing, IsInducing.isEmbedding⟩
```

-- snippet 5
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_nhds_injective (L106-L109)
theorem t0Space_iff_nhds_injective (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Injective (𝓝 : X → Filter X) :=
t0Space_iff_inseparable X
```

-- snippet 6
```lean
-- Mathlib.Topology.Separation.Basic.nhds_injective (L110-L112)
theorem nhds_injective [T0Space X] : Injective (𝓝 : X → Filter X) :=
(t0Space_iff_nhds_injective X).1 ‹_›
```

-- snippet 7
```lean
-- Mathlib.Topology.Separation.Basic.inseparable_iff_eq (L113-L115)
theorem inseparable_iff_eq [T0Space X] {x y : X} : Inseparable x y ↔ x = y :=
nhds_injective.eq_iff
```

-- snippet 8
```lean
-- Mathlib.Topology.Separation.Basic.nhds_eq_nhds_iff (L117-L119)
theorem nhds_eq_nhds_iff [T0Space X] {a b : X} : 𝓝 a = 𝓝 b ↔ a = b :=
nhds_injective.eq_iff
```

-- snippet 9
```lean
-- Mathlib.Topology.Separation.Basic.inseparable_eq_eq (L121-L123)
theorem inseparable_eq_eq [T0Space X] : Inseparable = @Eq X :=
funext₂ fun _ _ => propext inseparable_iff_eq
```

-- snippet 10
```lean
-- Mathlib.Topology.Separation.Basic.TopologicalSpace (L124-L130)
theorem TopologicalSpace.IsTopologicalBasis.inseparable_iff {b : Set (Set X)}
    (hb : IsTopologicalBasis b) {x y : X} : Inseparable x y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) :=
⟨fun h _ hs ↦ inseparable_iff_forall_isOpen.1 h _ (hb.isOpen hs),
    fun h ↦ hb.nhds_hasBasis.eq_of_same_basis <| by
      convert hb.nhds_hasBasis using 2
      exact and_congr_right (h _)⟩
```

-- snippet 11
```lean
-- Mathlib.Topology.Separation.Basic.TopologicalSpace (L131-L134)
theorem TopologicalSpace.IsTopologicalBasis.eq_iff [T0Space X] {b : Set (Set X)}
    (hb : IsTopologicalBasis b) {x y : X} : x = y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) :=
inseparable_iff_eq.symm.trans hb.inseparable_iff
```

-- snippet 12
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_exists_isOpen_xor'_mem (L135-L139)
theorem t0Space_iff_exists_isOpen_xor'_mem (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Pairwise fun x y => ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := by
simp only [t0Space_iff_not_inseparable, xor_iff_not_iff, not_forall, exists_prop,
    inseparable_iff_forall_isOpen, Pairwise]
```

-- snippet 13
```lean
-- Mathlib.Topology.Separation.Basic.exists_isOpen_xor'_mem (L140-L144)
theorem exists_isOpen_xor'_mem [T0Space X] {x y : X} (h : x ≠ y) :
    ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) :=
(t0Space_iff_exists_isOpen_xor'_mem X).1 ‹_› h

/-- Specialization forms a partial order on a t0 topological space. -/
```

-- snippet 14
```lean
-- Mathlib.Topology.Separation.Basic.specializationOrder (L146-L148)
def specializationOrder (X) [TopologicalSpace X] [T0Space X] : PartialOrder X :=
{ specializationPreorder X, PartialOrder.lift (OrderDual.toDual ∘ 𝓝) nhds_injective with }
```

-- snippet 15
```lean
-- Mathlib.Topology.Separation.Basic.SeparationQuotient (L149-L152)
instance SeparationQuotient.instT0Space : T0Space (SeparationQuotient X) :=
⟨fun x y => Quotient.inductionOn₂' x y fun _ _ h =>
    SeparationQuotient.mk_eq_mk.2 <| SeparationQuotient.isInducing_mk.inseparable_iff.1 h⟩
```

-- snippet 16
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_inf (L154-L158)
lemma completelyRegularSpace_inf {X : Type*} {t₁ t₂ : TopologicalSpace X}
    (ht₁ : @CompletelyRegularSpace X t₁) (ht₂ : @CompletelyRegularSpace X t₂) :
    @CompletelyRegularSpace X (t₁ ⊓ t₂) := by
rw [inf_eq_iInf]; apply completelyRegularSpace_iInf; simp [*]
```

-- snippet 17
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iff_isOpen (L72-L78)
lemma completelyRegularSpace_iff_isOpen : CompletelyRegularSpace X ↔
    ∀ (x : X), ∀ K : Set X, IsOpen K → x ∈ K →
      ∃ f : X → I, Continuous f ∧ f x = 0 ∧ EqOn f 1 Kᶜ := by
conv_lhs => tactic =>
    simp_rw +singlePass [completelyRegularSpace_iff, compl_surjective.forall, isClosed_compl_iff,
      mem_compl_iff, not_not]
```

-- snippet 18
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.Topology (L109-L120)
lemma Topology.IsInducing.completelyRegularSpace
    {Y : Type v} [TopologicalSpace Y] [CompletelyRegularSpace Y]
    {f : X → Y} (hf : IsInducing f) : CompletelyRegularSpace X where
  completely_regular x K hK hxK := by
rw [hf.isClosed_iff] at hK
    obtain ⟨K, hK, rfl⟩ := hK
    rw [mem_preimage] at hxK
    obtain ⟨g, hcf, egfx, hgK⟩ := CompletelyRegularSpace.completely_regular _ _ hK hxK
    refine ⟨g ∘ f, hcf.comp hf.continuous, egfx, ?_⟩
    conv => arg 2; equals (1 : Y → ↥I) ∘ f => rfl
    exact hgK.comp_right <| mapsTo_preimage _ _
```

-- snippet 19
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.t35Space_iff_isEmbedding_stoneCechUnit (L270-L273)
lemma t35Space_iff_isEmbedding_stoneCechUnit :
    T35Space X ↔ IsEmbedding (stoneCechUnit : X → StoneCech X) where
  mp _ := isEmbedding_stoneCechUnit
mpr hs := hs.t35Space
```

-- snippet 20
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isDenseInducing_stoneCechUnit (L186-L190)
lemma isDenseInducing_stoneCechUnit [CompletelyRegularSpace X] :
    IsDenseInducing (stoneCechUnit : X → StoneCech X) where
  toIsInducing := isInducing_stoneCechUnit
dense := denseRange_stoneCechUnit
```

-- snippet 21
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.separatesPoints_continuous_of_t35Space (L239-L245)
lemma separatesPoints_continuous_of_t35Space [T35Space X] :
    SeparatesPoints {f : X → ℝ | Continuous f} := by
intro x y x_ne_y
  obtain ⟨f, f_cont, f_zero, f_one⟩ :=
    CompletelyRegularSpace.completely_regular x {y} isClosed_singleton x_ne_y
  exact ⟨fun x ↦ f x, continuous_subtype_val.comp f_cont, by simp_all⟩
```

-- snippet 22
```lean
-- Mathlib.Topology.Separation.Connected.PreconnectedSpace (L30-L35)
theorem PreconnectedSpace.trivial_of_discrete [PreconnectedSpace X] [DiscreteTopology X] :
    Subsingleton X := by
by_contra! ⟨x, y, hxy⟩
  rw [Ne, ← mem_singleton_iff, (isClopen_discrete _).eq_univ <| singleton_nonempty y] at hxy
  exact hxy (mem_univ x)
```

-- snippet 23
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isDenseEmbedding_stoneCechUnit (L265-L269)
lemma isDenseEmbedding_stoneCechUnit [T35Space X] :
    IsDenseEmbedding (stoneCechUnit : X → StoneCech X) where
  toIsDenseInducing := isDenseInducing_stoneCechUnit
injective := injective_stoneCechUnit_of_t35Space
```

-- snippet 24
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isInducing_stoneCechUnit (L169-L185)
lemma isInducing_stoneCechUnit [CompletelyRegularSpace X] :
    IsInducing (stoneCechUnit : X → StoneCech X) := by
rw [isInducing_iff_nhds]
  intro x
  apply le_antisymm
  · rw [← map_le_iff_le_comap]; exact continuous_stoneCechUnit.continuousAt
  · simp_rw [le_nhds_iff, ((nhds_basis_opens _).comap _).mem_iff, and_assoc]
    intro U hxU hU
    obtain ⟨f, hf, efx, hfU⟩ :=
      CompletelyRegularSpace.completely_regular_isOpen x U hU hxU
    conv at hfU => equals Uᶜ ⊆ f ⁻¹' {1} => simp [EqOn, subset_def]
    rw [← compl_subset_comm, ← preimage_compl, ← stoneCechExtend_extends hf, preimage_comp] at hfU
    refine ⟨stoneCechExtend hf ⁻¹' {1}ᶜ, ?_,
      isOpen_compl_singleton.preimage (continuous_stoneCechExtend hf), hfU⟩
    rw [mem_preimage, stoneCechExtend_stoneCechUnit, efx, mem_compl_iff, mem_singleton_iff]
    simp
```

-- snippet 25
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_nonempty_disjoint_clopen_cover (L56-L78)
lemma exists_finite_nonempty_disjoint_clopen_cover (hU : IsOpenCover U) :
    ∃ (n : ℕ) (W : Fin n → Clopens X), (∀ j, W j ≠ ⊥ ∧ ∃ i, (W j : Set X) ⊆ U i)
    ∧ (univ : Set X) ⊆ ⋃ j, ↑(W j) ∧ Pairwise (Disjoint on W) := by
classical
  obtain ⟨n, V, hVle, hVun⟩ := hU.exists_finite_clopen_cover
  obtain ⟨W, hWle, hWun, hWd⟩ := Fintype.exists_disjointed_le V
  simp only [← SetLike.coe_set_eq, Clopens.coe_finset_sup, Finset.mem_univ, iUnion_true] at hWun
  let t : Finset (Fin n) := {j | W j ≠ ⊥}
  refine ⟨#t, fun k ↦ W (t.equivFin.symm k), fun k ↦ ⟨?_, ?_⟩, fun x hx ↦ ?_, ?_⟩
  · exact (Finset.mem_filter.mp (t.equivFin.symm k).2).2
  · exact match hVle (t.equivFin.symm k) with | ⟨i, hi⟩ => ⟨i, subset_trans (hWle _) hi⟩
  · obtain ⟨j, hj⟩ := mem_iUnion.mp <| (hWun ▸ hVun) hx
    have : W j ≠ ⊥ := by simpa [← SetLike.coe_ne_coe, ← Set.nonempty_iff_ne_empty] using ⟨x, hj⟩
    exact mem_iUnion.mpr ⟨t.equivFin ⟨j, Finset.mem_filter.mpr ⟨Finset.mem_univ _, this⟩⟩, by simpa⟩
  · exact hWd.comp_of_injective <| Subtype.val_injective.comp t.equivFin.symm.injective

end TopologicalSpace.IsOpenCover

namespace TopologicalSpace
variable {X : Type*} [TopologicalSpace X] {S : Set (X × X)}

/-- If `S` is any neighbourhood of the diagonal in a topological space `X`, any point of `X` has an
open neighbourhood `U` such that `U ×ˢ U ⊆ S`. -/
```

-- snippet 26
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal (L127-L139)
lemma exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal V)) :
    ∃ (n : ℕ) (D : Fin n → Clopens X), (∀ i, D i ≠ ⊥) ∧ (∀ i, ∀ y ∈ D i, ∀ z ∈ D i, (f y, f z) ∈ S)
    ∧ (univ : Set X) ⊆ ⋃ i, D i ∧ Pairwise (Disjoint on D) := by
have : (f.prodMap f) ⁻¹' S ∈ nhdsSet (diagonal X) := by
    rw [mem_nhdsSet_iff_forall] at hS ⊢
    rintro ⟨x, y⟩ (rfl : x = y)
    exact (map_continuous _).continuousAt.preimage_mem_nhds (hS _ rfl)
  exact exists_finite_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal_of_profinite this

/--
For any continuous function `f : X → V`, with `X` profinite, and `S` a neighbourhood of the
diagonal in `V × V`, the function `f` can be `S`-approximated by a function factoring through
`Fin n`, for some `n`. -/
```

-- snippet 27
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.NormalSpace (L93-L108)
instance NormalSpace.instCompletelyRegularSpace [NormalSpace X] [R0Space X] :
    CompletelyRegularSpace X := by
rw [completelyRegularSpace_iff]
  intro x K hK hx
  have cx : IsClosed (closure {x}) := isClosed_closure
  have d : Disjoint (closure {x}) K := by
    rw [Set.disjoint_iff]
    intro a ⟨hax, haK⟩
    exact hx ((specializes_iff_mem_closure.mpr hax).symm.mem_closed hK haK)
  let ⟨⟨f, cf⟩, hfx, hfK, hficc⟩ := exists_continuous_zero_one_of_isClosed cx hK d
  let g : X → I := fun x => ⟨f x, hficc x⟩
  have cg : Continuous g := cf.subtype_mk hficc
  have hgx : g x = 0 := Subtype.ext (hfx (subset_closure (mem_singleton x)))
  have hgK : EqOn g 1 K := fun k hk => Subtype.ext (hfK hk)
  exact ⟨g, cg, hgx, hgK⟩
```

-- snippet 28
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact (L92-L126)
lemma exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact
    (hS : S ∈ nhdsSet (diagonal X)) :
    ∃ (t : Finset X) (U : t → Opens X), IsOpenCover U ∧ ∀ i, (U i : Set X) ×ˢ U i ⊆ S := by
choose U hUo hUx hUp using exists_open_prod_subset_of_mem_nhds_diagonal hS
  obtain ⟨t, ht⟩ := isCompact_univ.elim_finite_subcover _ hUo (fun x _ ↦ mem_iUnion.mpr ⟨_, hUx x⟩)
  refine ⟨t, fun i ↦ ⟨_, hUo i⟩, .of_sets _ ?_, (hUp ·)⟩
  simpa [iUnion_subtype, ← univ_subset_iff] using ht

variable [TotallyDisconnectedSpace X] [T2Space X]

/-- If `S` is any neighbourhood of the diagonal in a profinite topological space `X`, then there
exists a finite cover of `X` by disjoint nonempty clopens `U i` with `U i ×ˢ U i ⊆ S` for all `i`.
-/
private lemma exists_finite_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal_of_profinite
    (hS : S ∈ nhdsSet (diagonal X)) :
    ∃ (n : ℕ) (D : Fin n → Clopens X), (∀ i, D i ≠ ⊥) ∧ (∀ i, ∀ y ∈ D i, ∀ z ∈ D i, (y, z) ∈ S)
    ∧ (univ : Set X) ⊆ ⋃ i, D i ∧ Pairwise (Disjoint on D) := by
  obtain ⟨t, U, hUc, hUS⟩ := exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact hS
  -- Now refine it to a disjoint covering.
  obtain ⟨n, W, hW₁, hW₂, hW₃⟩ := hUc.exists_finite_nonempty_disjoint_clopen_cover
  refine ⟨n, W, fun j ↦ (hW₁ j).1, fun j y hy z hz ↦ ?_, hW₂, hW₃⟩
  exact match (hW₁ j).2 with | ⟨i, hi⟩ => hUS i ⟨hi hy, hi hz⟩

end TopologicalSpace

namespace ContinuousMap

variable {X V : Type*} [TopologicalSpace X] [TopologicalSpace V] [TotallyDisconnectedSpace X]
  [T2Space X] [CompactSpace X] {S : Set (V × V)} (f : C(X, V))

/--
For any continuous function `f : X → V`, with `X` profinite, and `S` a neighbourhood of the
diagonal in `V × V`, there exists a finite cover of `X` by pairwise-disjoint nonempty clopens, on
each of which `f` varies within `S`.
-/
```

-- snippet 29
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_clopen_cover (L40-L55)
lemma exists_finite_clopen_cover (hU : IsOpenCover U) : ∃ (n : ℕ) (V : Fin n → Clopens X),
    (∀ j, ∃ i, (V j : Set X) ⊆ U i) ∧ univ ⊆ ⋃ j, (V j : Set X) := by
-- Choose an index `r x` for each point in `X` such that `∀ x, x ∈ U (r x)`.
  choose r hr using hU.exists_mem
  -- Choose a clopen neighbourhood `V x` of each `x` contained in `U (r x)`.
  choose V hV hVx hVU using fun x ↦ compact_exists_isClopen_in_isOpen (U _).isOpen (hr x)
  -- Apply compactness to extract a finite subset of the `V`s which covers `X`.
  obtain ⟨t, ht⟩ : ∃ t, univ ⊆ ⋃ i ∈ t, V i :=
    isCompact_univ.elim_finite_subcover V (fun x ↦ (hV x).2) (fun x _ ↦ mem_iUnion.mpr ⟨x, hVx x⟩)
  -- Biject it noncanonically with `Fin n` for some `n`.
  refine ⟨_, fun j ↦ ⟨_, hV (t.equivFin.symm j)⟩, fun j ↦ ⟨_, hVU _⟩, fun x hx ↦ ?_⟩
  obtain ⟨m, hm, hm'⟩ := mem_iUnion₂.mp (ht hx)
  exact Set.mem_iUnion_of_mem (t.equivFin ⟨m, hm⟩) (by simpa)

/-- Any open cover of a profinite space can be refined to a finite cover by pairwise disjoint
nonempty clopens. -/
```

-- snippet 30
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iInf (L129-L153)
lemma completelyRegularSpace_iInf {ι X : Type*} {t : ι → TopologicalSpace X}
    (ht : ∀ i, @CompletelyRegularSpace X (t i)) : @CompletelyRegularSpace X (⨅ i, t i) := by
letI := (⨅ i, t i) -- register this as default topological space to reduce `@`s
  rw [completelyRegularSpace_iff_isOpen]
  intro x K hK hxK
  simp_rw [← hK.mem_nhds_iff, nhds_iInf, mem_iInf, exists_finite_iff_finset,
    Finset.coe_sort_coe] at hxK; clear hK
  obtain ⟨I', V, hV, rfl⟩ := hxK
  simp only [mem_nhds_iff] at hV
  choose U hUV hU hxU using hV
  replace hU := fun (i : ↥I') =>
    @CompletelyRegularSpace.completely_regular_isOpen _ (t i) (ht i) x (U i) (hU i) (hxU i)
  clear hxU
  choose fs hfs hxfs hfsU using hU
  use I'.attach.sup fs
  constructorm* _ ∧ _
  · solve_by_elim [Continuous.finset_sup, continuous_iInf_dom]
  · simpa [show (0 : ↥I) = ⊥ from rfl] using hxfs
  · simp only [EqOn, Pi.one_apply, show (1 : ↥I) = ⊤ from rfl] at hfsU ⊢
    conv => equals ∀ x i, x ∈ (V i)ᶜ → ∃ b, fs b x = ⊤ => simp [Finset.sup_eq_top_iff]
    intro x i hxi
    specialize hfsU i (by tauto_set)
    exists i

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 31
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iff_isInducing_stoneCechUnit (L191-L196)
lemma completelyRegularSpace_iff_isInducing_stoneCechUnit :
    CompletelyRegularSpace X ↔ IsInducing (stoneCechUnit : X → StoneCech X) where
  mp _ := isInducing_stoneCechUnit
mpr hs := hs.completelyRegularSpace

open TopologicalSpace Cardinal in
```

-- snippet 32
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_approximation_of_mem_nhds_diagonal (L140-L161)
lemma exists_finite_approximation_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal V)) :
    ∃ (n : ℕ) (g : X → Fin n) (h : Fin n → V), Continuous g ∧ ∀ x, (f x, h (g x)) ∈ S := by
obtain ⟨n, E, hEne, hES, hEuniv, hEdis⟩ :=
    exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal f hS
  have h_uniq (x) : ∃! i, x ∈ E i := by
    refine match mem_iUnion.mp (hEuniv <| mem_univ x) with
      | ⟨i, hi⟩ => ⟨i, hi, fun j hj ↦ hEdis.eq ?_⟩
    simpa [← Clopens.coe_disjoint, not_disjoint_iff] using ⟨x, hj, hi⟩
  choose g hg hg' using h_uniq -- for each `x`, `g x` is the unique `i` such that `x ∈ E i`
  have h_ex (i) : ∃ x, x ∈ E i := by
    simpa [← SetLike.coe_set_eq, ← nonempty_iff_ne_empty] using hEne i
  choose r hr using h_ex -- for each `i`, choose an `r i ∈ E i`
  refine ⟨n, g, f ∘ r, continuous_discrete_rng.mpr fun j ↦ ?_, fun x ↦ (hES _) _ (hg _) _ (hr _)⟩
  convert (E j).isOpen
  exact Set.ext fun x ↦ ⟨fun hj ↦ hj ▸ hg x, fun hx ↦ (hg' _ _ hx).symm⟩

/--
If `f` is a continuous map from a profinite space to a topological space with a commutative monoid
structure, then we can approximate `f` by finite products of indicator functions of clopen sets.

(Note no compatibility is assumed between the monoid structure on `V` and the topology.)
-/
```

-- snippet 33
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_open_prod_subset_of_mem_nhds_diagonal (L79-L91)
lemma exists_open_prod_subset_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal X)) (x : X) :
    ∃ U : Set X, IsOpen U ∧ x ∈ U ∧ U ×ˢ U ⊆ S := by
have : S ∈ 𝓝 (x, x) := mem_nhdsSet_iff_forall.mp hS _ rfl
  obtain ⟨u, v, huo, hux, hvo, hvx, H⟩ := by rwa [mem_nhds_prod_iff'] at this
  exact ⟨_, huo.inter hvo, ⟨hux, hvx⟩, fun p hp ↦ H ⟨hp.1.1, hp.2.2⟩⟩

variable [CompactSpace X]

/-- If `S` is any neighbourhood of the diagonal in a compact topological space `X`, then there
exists a finite cover of `X` by opens `U i` such that `U i ×ˢ U i ⊆ S` for all `i`.

That the indexing set is a finset of `X` is an artifact of the proof; it could be any finite type.
-/
```

-- snippet 34
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_induced (L124-L128)
lemma completelyRegularSpace_induced
    {X Y : Type*} {t : TopologicalSpace Y} (ht : @CompletelyRegularSpace Y t)
    (f : X → Y) : @CompletelyRegularSpace X (t.induced f) :=
@IsInducing.completelyRegularSpace _ (t.induced f) _ t _ _ (IsInducing.induced f)
```

-- snippet 35
```lean
-- Mathlib.Topology.Separation.AlexandrovDiscrete.nhdsKer_eq_of_t1Space (L22-L24)
lemma nhdsKer_eq_of_t1Space [T1Space X] (s : Set X) : nhdsKer s = s := by
ext; simp [mem_nhdsKer_iff_specializes]
```

-- snippet 36
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isEmbedding_stoneCechUnit (L260-L264)
lemma isEmbedding_stoneCechUnit [T35Space X] :
    IsEmbedding (stoneCechUnit : X → StoneCech X) where
  toIsInducing := isInducing_stoneCechUnit
injective := injective_stoneCechUnit_of_t35Space
```

-- snippet 37
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.CompletelyRegularSpace (L79-L83)
lemma CompletelyRegularSpace.completely_regular_isOpen [CompletelyRegularSpace X] :
    ∀ (x : X), ∀ K : Set X, IsOpen K → x ∈ K →
      ∃ f : X → I, Continuous f ∧ f x = 0 ∧ EqOn f 1 Kᶜ :=
completelyRegularSpace_iff_isOpen.mp inferInstance
```

-- snippet 38
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.injective_stoneCechUnit_of_t35Space (L253-L259)
lemma injective_stoneCechUnit_of_t35Space [T35Space X] :
    Function.Injective (stoneCechUnit : X → StoneCech X) := by
intro a b hab
  contrapose hab
  obtain ⟨f, fc, fab⟩ := separatesPoints_continuous_of_t35Space_Icc hab
  exact fun q ↦ fab (eq_if_stoneCechUnit_eq fc q)
```

-- snippet 39
```lean
-- Mathlib.Topology.Separation.Connected.IsPreconnected (L36-L41)
theorem IsPreconnected.infinite_of_nontrivial [T1Space X] {s : Set X} (h : IsPreconnected s)
    (hs : s.Nontrivial) : s.Infinite := by
refine mt (fun hf => (subsingleton_coe s).mp ?_) (not_subsingleton_iff.mpr hs)
  haveI := @Finite.instDiscreteTopology s _ _ hf.to_subtype
  exact @PreconnectedSpace.trivial_of_discrete _ _ (Subtype.preconnectedSpace h) _
```

-- snippet 40
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.separatesPoints_continuous_of_t35Space_Icc (L246-L252)
lemma separatesPoints_continuous_of_t35Space_Icc [T35Space X] :
    SeparatesPoints {f : X → I | Continuous f} := by
intro x y x_ne_y
  obtain ⟨f, f_cont, f_zero, f_one⟩ :=
    CompletelyRegularSpace.completely_regular x {y} isClosed_singleton x_ne_y
  exact ⟨f, f_cont, by simp_all⟩
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Topology.Separation.Basic).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem IsCompact.closure_of_subset {s K : Set X} (hK : IsCompact K) (h : s ⊆ K) :
    IsCompact (closure s)
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_inseparable (L81-L84)
theorem t0Space_iff_inseparable (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ ∀ x y : X, Inseparable x y → x = y :=
⟨fun ⟨h⟩ => h, fun h => ⟨h⟩⟩
```

-- snippet 2
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_not_inseparable (L85-L88)
theorem t0Space_iff_not_inseparable (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Pairwise fun x y : X => ¬Inseparable x y := by
simp only [t0Space_iff_inseparable, Ne, not_imp_not, Pairwise]
```

-- snippet 3
```lean
-- Mathlib.Topology.Separation.Basic.Inseparable (L89-L101)
theorem Inseparable.eq [T0Space X] {x y : X} (h : Inseparable x y) : x = y :=
T0Space.t0 h

/-- A topology inducing map from a T₀ space is injective. -/
protected theorem Topology.IsInducing.injective [TopologicalSpace Y] [T0Space X] {f : X → Y}
    (hf : IsInducing f) : Injective f := fun _ _ h =>
  (hf.inseparable_iff.1 <| .of_eq h).eq

/-- A topology inducing map from a T₀ space is a topological embedding. -/
protected theorem Topology.IsInducing.isEmbedding [TopologicalSpace Y] [T0Space X] {f : X → Y}
    (hf : IsInducing f) : IsEmbedding f :=
  ⟨hf, hf.injective⟩
```

-- snippet 4
```lean
-- Mathlib.Topology.Separation.Basic.isEmbedding_iff_isInducing (L102-L105)
lemma isEmbedding_iff_isInducing [TopologicalSpace Y] [T0Space X] {f : X → Y} :
    IsEmbedding f ↔ IsInducing f :=
⟨IsEmbedding.isInducing, IsInducing.isEmbedding⟩
```

-- snippet 5
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_nhds_injective (L106-L109)
theorem t0Space_iff_nhds_injective (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Injective (𝓝 : X → Filter X) :=
t0Space_iff_inseparable X
```

-- snippet 6
```lean
-- Mathlib.Topology.Separation.Basic.nhds_injective (L110-L112)
theorem nhds_injective [T0Space X] : Injective (𝓝 : X → Filter X) :=
(t0Space_iff_nhds_injective X).1 ‹_›
```

-- snippet 7
```lean
-- Mathlib.Topology.Separation.Basic.inseparable_iff_eq (L113-L115)
theorem inseparable_iff_eq [T0Space X] {x y : X} : Inseparable x y ↔ x = y :=
nhds_injective.eq_iff
```

-- snippet 8
```lean
-- Mathlib.Topology.Separation.Basic.nhds_eq_nhds_iff (L117-L119)
theorem nhds_eq_nhds_iff [T0Space X] {a b : X} : 𝓝 a = 𝓝 b ↔ a = b :=
nhds_injective.eq_iff
```

-- snippet 9
```lean
-- Mathlib.Topology.Separation.Basic.inseparable_eq_eq (L121-L123)
theorem inseparable_eq_eq [T0Space X] : Inseparable = @Eq X :=
funext₂ fun _ _ => propext inseparable_iff_eq
```

-- snippet 10
```lean
-- Mathlib.Topology.Separation.Basic.TopologicalSpace (L124-L130)
theorem TopologicalSpace.IsTopologicalBasis.inseparable_iff {b : Set (Set X)}
    (hb : IsTopologicalBasis b) {x y : X} : Inseparable x y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) :=
⟨fun h _ hs ↦ inseparable_iff_forall_isOpen.1 h _ (hb.isOpen hs),
    fun h ↦ hb.nhds_hasBasis.eq_of_same_basis <| by
      convert hb.nhds_hasBasis using 2
      exact and_congr_right (h _)⟩
```

-- snippet 11
```lean
-- Mathlib.Topology.Separation.Basic.TopologicalSpace (L131-L134)
theorem TopologicalSpace.IsTopologicalBasis.eq_iff [T0Space X] {b : Set (Set X)}
    (hb : IsTopologicalBasis b) {x y : X} : x = y ↔ ∀ s ∈ b, (x ∈ s ↔ y ∈ s) :=
inseparable_iff_eq.symm.trans hb.inseparable_iff
```

-- snippet 12
```lean
-- Mathlib.Topology.Separation.Basic.t0Space_iff_exists_isOpen_xor'_mem (L135-L139)
theorem t0Space_iff_exists_isOpen_xor'_mem (X : Type u) [TopologicalSpace X] :
    T0Space X ↔ Pairwise fun x y => ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) := by
simp only [t0Space_iff_not_inseparable, xor_iff_not_iff, not_forall, exists_prop,
    inseparable_iff_forall_isOpen, Pairwise]
```

-- snippet 13
```lean
-- Mathlib.Topology.Separation.Basic.exists_isOpen_xor'_mem (L140-L144)
theorem exists_isOpen_xor'_mem [T0Space X] {x y : X} (h : x ≠ y) :
    ∃ U : Set X, IsOpen U ∧ Xor' (x ∈ U) (y ∈ U) :=
(t0Space_iff_exists_isOpen_xor'_mem X).1 ‹_› h

/-- Specialization forms a partial order on a t0 topological space. -/
```

-- snippet 14
```lean
-- Mathlib.Topology.Separation.Basic.specializationOrder (L146-L148)
def specializationOrder (X) [TopologicalSpace X] [T0Space X] : PartialOrder X :=
{ specializationPreorder X, PartialOrder.lift (OrderDual.toDual ∘ 𝓝) nhds_injective with }
```

-- snippet 15
```lean
-- Mathlib.Topology.Separation.Basic.SeparationQuotient (L149-L152)
instance SeparationQuotient.instT0Space : T0Space (SeparationQuotient X) :=
⟨fun x y => Quotient.inductionOn₂' x y fun _ _ h =>
    SeparationQuotient.mk_eq_mk.2 <| SeparationQuotient.isInducing_mk.inseparable_iff.1 h⟩
```

-- snippet 16
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_inf (L154-L158)
lemma completelyRegularSpace_inf {X : Type*} {t₁ t₂ : TopologicalSpace X}
    (ht₁ : @CompletelyRegularSpace X t₁) (ht₂ : @CompletelyRegularSpace X t₂) :
    @CompletelyRegularSpace X (t₁ ⊓ t₂) := by
rw [inf_eq_iInf]; apply completelyRegularSpace_iInf; simp [*]
```

-- snippet 17
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iff_isOpen (L72-L78)
lemma completelyRegularSpace_iff_isOpen : CompletelyRegularSpace X ↔
    ∀ (x : X), ∀ K : Set X, IsOpen K → x ∈ K →
      ∃ f : X → I, Continuous f ∧ f x = 0 ∧ EqOn f 1 Kᶜ := by
conv_lhs => tactic =>
    simp_rw +singlePass [completelyRegularSpace_iff, compl_surjective.forall, isClosed_compl_iff,
      mem_compl_iff, not_not]
```

-- snippet 18
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.Topology (L109-L120)
lemma Topology.IsInducing.completelyRegularSpace
    {Y : Type v} [TopologicalSpace Y] [CompletelyRegularSpace Y]
    {f : X → Y} (hf : IsInducing f) : CompletelyRegularSpace X where
  completely_regular x K hK hxK := by
rw [hf.isClosed_iff] at hK
    obtain ⟨K, hK, rfl⟩ := hK
    rw [mem_preimage] at hxK
    obtain ⟨g, hcf, egfx, hgK⟩ := CompletelyRegularSpace.completely_regular _ _ hK hxK
    refine ⟨g ∘ f, hcf.comp hf.continuous, egfx, ?_⟩
    conv => arg 2; equals (1 : Y → ↥I) ∘ f => rfl
    exact hgK.comp_right <| mapsTo_preimage _ _
```

-- snippet 19
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.t35Space_iff_isEmbedding_stoneCechUnit (L270-L273)
lemma t35Space_iff_isEmbedding_stoneCechUnit :
    T35Space X ↔ IsEmbedding (stoneCechUnit : X → StoneCech X) where
  mp _ := isEmbedding_stoneCechUnit
mpr hs := hs.t35Space
```

-- snippet 20
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isDenseInducing_stoneCechUnit (L186-L190)
lemma isDenseInducing_stoneCechUnit [CompletelyRegularSpace X] :
    IsDenseInducing (stoneCechUnit : X → StoneCech X) where
  toIsInducing := isInducing_stoneCechUnit
dense := denseRange_stoneCechUnit
```

-- snippet 21
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.separatesPoints_continuous_of_t35Space (L239-L245)
lemma separatesPoints_continuous_of_t35Space [T35Space X] :
    SeparatesPoints {f : X → ℝ | Continuous f} := by
intro x y x_ne_y
  obtain ⟨f, f_cont, f_zero, f_one⟩ :=
    CompletelyRegularSpace.completely_regular x {y} isClosed_singleton x_ne_y
  exact ⟨fun x ↦ f x, continuous_subtype_val.comp f_cont, by simp_all⟩
```

-- snippet 22
```lean
-- Mathlib.Topology.Separation.Connected.PreconnectedSpace (L30-L35)
theorem PreconnectedSpace.trivial_of_discrete [PreconnectedSpace X] [DiscreteTopology X] :
    Subsingleton X := by
by_contra! ⟨x, y, hxy⟩
  rw [Ne, ← mem_singleton_iff, (isClopen_discrete _).eq_univ <| singleton_nonempty y] at hxy
  exact hxy (mem_univ x)
```

-- snippet 23
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isDenseEmbedding_stoneCechUnit (L265-L269)
lemma isDenseEmbedding_stoneCechUnit [T35Space X] :
    IsDenseEmbedding (stoneCechUnit : X → StoneCech X) where
  toIsDenseInducing := isDenseInducing_stoneCechUnit
injective := injective_stoneCechUnit_of_t35Space
```

-- snippet 24
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isInducing_stoneCechUnit (L169-L185)
lemma isInducing_stoneCechUnit [CompletelyRegularSpace X] :
    IsInducing (stoneCechUnit : X → StoneCech X) := by
rw [isInducing_iff_nhds]
  intro x
  apply le_antisymm
  · rw [← map_le_iff_le_comap]; exact continuous_stoneCechUnit.continuousAt
  · simp_rw [le_nhds_iff, ((nhds_basis_opens _).comap _).mem_iff, and_assoc]
    intro U hxU hU
    obtain ⟨f, hf, efx, hfU⟩ :=
      CompletelyRegularSpace.completely_regular_isOpen x U hU hxU
    conv at hfU => equals Uᶜ ⊆ f ⁻¹' {1} => simp [EqOn, subset_def]
    rw [← compl_subset_comm, ← preimage_compl, ← stoneCechExtend_extends hf, preimage_comp] at hfU
    refine ⟨stoneCechExtend hf ⁻¹' {1}ᶜ, ?_,
      isOpen_compl_singleton.preimage (continuous_stoneCechExtend hf), hfU⟩
    rw [mem_preimage, stoneCechExtend_stoneCechUnit, efx, mem_compl_iff, mem_singleton_iff]
    simp
```

-- snippet 25
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_nonempty_disjoint_clopen_cover (L56-L78)
lemma exists_finite_nonempty_disjoint_clopen_cover (hU : IsOpenCover U) :
    ∃ (n : ℕ) (W : Fin n → Clopens X), (∀ j, W j ≠ ⊥ ∧ ∃ i, (W j : Set X) ⊆ U i)
    ∧ (univ : Set X) ⊆ ⋃ j, ↑(W j) ∧ Pairwise (Disjoint on W) := by
classical
  obtain ⟨n, V, hVle, hVun⟩ := hU.exists_finite_clopen_cover
  obtain ⟨W, hWle, hWun, hWd⟩ := Fintype.exists_disjointed_le V
  simp only [← SetLike.coe_set_eq, Clopens.coe_finset_sup, Finset.mem_univ, iUnion_true] at hWun
  let t : Finset (Fin n) := {j | W j ≠ ⊥}
  refine ⟨#t, fun k ↦ W (t.equivFin.symm k), fun k ↦ ⟨?_, ?_⟩, fun x hx ↦ ?_, ?_⟩
  · exact (Finset.mem_filter.mp (t.equivFin.symm k).2).2
  · exact match hVle (t.equivFin.symm k) with | ⟨i, hi⟩ => ⟨i, subset_trans (hWle _) hi⟩
  · obtain ⟨j, hj⟩ := mem_iUnion.mp <| (hWun ▸ hVun) hx
    have : W j ≠ ⊥ := by simpa [← SetLike.coe_ne_coe, ← Set.nonempty_iff_ne_empty] using ⟨x, hj⟩
    exact mem_iUnion.mpr ⟨t.equivFin ⟨j, Finset.mem_filter.mpr ⟨Finset.mem_univ _, this⟩⟩, by simpa⟩
  · exact hWd.comp_of_injective <| Subtype.val_injective.comp t.equivFin.symm.injective

end TopologicalSpace.IsOpenCover

namespace TopologicalSpace
variable {X : Type*} [TopologicalSpace X] {S : Set (X × X)}

/-- If `S` is any neighbourhood of the diagonal in a topological space `X`, any point of `X` has an
open neighbourhood `U` such that `U ×ˢ U ⊆ S`. -/
```

-- snippet 26
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal (L127-L139)
lemma exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal V)) :
    ∃ (n : ℕ) (D : Fin n → Clopens X), (∀ i, D i ≠ ⊥) ∧ (∀ i, ∀ y ∈ D i, ∀ z ∈ D i, (f y, f z) ∈ S)
    ∧ (univ : Set X) ⊆ ⋃ i, D i ∧ Pairwise (Disjoint on D) := by
have : (f.prodMap f) ⁻¹' S ∈ nhdsSet (diagonal X) := by
    rw [mem_nhdsSet_iff_forall] at hS ⊢
    rintro ⟨x, y⟩ (rfl : x = y)
    exact (map_continuous _).continuousAt.preimage_mem_nhds (hS _ rfl)
  exact exists_finite_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal_of_profinite this

/--
For any continuous function `f : X → V`, with `X` profinite, and `S` a neighbourhood of the
diagonal in `V × V`, the function `f` can be `S`-approximated by a function factoring through
`Fin n`, for some `n`. -/
```

-- snippet 27
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.NormalSpace (L93-L108)
instance NormalSpace.instCompletelyRegularSpace [NormalSpace X] [R0Space X] :
    CompletelyRegularSpace X := by
rw [completelyRegularSpace_iff]
  intro x K hK hx
  have cx : IsClosed (closure {x}) := isClosed_closure
  have d : Disjoint (closure {x}) K := by
    rw [Set.disjoint_iff]
    intro a ⟨hax, haK⟩
    exact hx ((specializes_iff_mem_closure.mpr hax).symm.mem_closed hK haK)
  let ⟨⟨f, cf⟩, hfx, hfK, hficc⟩ := exists_continuous_zero_one_of_isClosed cx hK d
  let g : X → I := fun x => ⟨f x, hficc x⟩
  have cg : Continuous g := cf.subtype_mk hficc
  have hgx : g x = 0 := Subtype.ext (hfx (subset_closure (mem_singleton x)))
  have hgK : EqOn g 1 K := fun k hk => Subtype.ext (hfK hk)
  exact ⟨g, cg, hgx, hgK⟩
```

-- snippet 28
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact (L92-L126)
lemma exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact
    (hS : S ∈ nhdsSet (diagonal X)) :
    ∃ (t : Finset X) (U : t → Opens X), IsOpenCover U ∧ ∀ i, (U i : Set X) ×ˢ U i ⊆ S := by
choose U hUo hUx hUp using exists_open_prod_subset_of_mem_nhds_diagonal hS
  obtain ⟨t, ht⟩ := isCompact_univ.elim_finite_subcover _ hUo (fun x _ ↦ mem_iUnion.mpr ⟨_, hUx x⟩)
  refine ⟨t, fun i ↦ ⟨_, hUo i⟩, .of_sets _ ?_, (hUp ·)⟩
  simpa [iUnion_subtype, ← univ_subset_iff] using ht

variable [TotallyDisconnectedSpace X] [T2Space X]

/-- If `S` is any neighbourhood of the diagonal in a profinite topological space `X`, then there
exists a finite cover of `X` by disjoint nonempty clopens `U i` with `U i ×ˢ U i ⊆ S` for all `i`.
-/
private lemma exists_finite_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal_of_profinite
    (hS : S ∈ nhdsSet (diagonal X)) :
    ∃ (n : ℕ) (D : Fin n → Clopens X), (∀ i, D i ≠ ⊥) ∧ (∀ i, ∀ y ∈ D i, ∀ z ∈ D i, (y, z) ∈ S)
    ∧ (univ : Set X) ⊆ ⋃ i, D i ∧ Pairwise (Disjoint on D) := by
  obtain ⟨t, U, hUc, hUS⟩ := exists_finite_open_cover_prod_subset_of_mem_nhds_diagonal_of_compact hS
  -- Now refine it to a disjoint covering.
  obtain ⟨n, W, hW₁, hW₂, hW₃⟩ := hUc.exists_finite_nonempty_disjoint_clopen_cover
  refine ⟨n, W, fun j ↦ (hW₁ j).1, fun j y hy z hz ↦ ?_, hW₂, hW₃⟩
  exact match (hW₁ j).2 with | ⟨i, hi⟩ => hUS i ⟨hi hy, hi hz⟩

end TopologicalSpace

namespace ContinuousMap

variable {X V : Type*} [TopologicalSpace X] [TopologicalSpace V] [TotallyDisconnectedSpace X]
  [T2Space X] [CompactSpace X] {S : Set (V × V)} (f : C(X, V))

/--
For any continuous function `f : X → V`, with `X` profinite, and `S` a neighbourhood of the
diagonal in `V × V`, there exists a finite cover of `X` by pairwise-disjoint nonempty clopens, on
each of which `f` varies within `S`.
-/
```

-- snippet 29
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_clopen_cover (L40-L55)
lemma exists_finite_clopen_cover (hU : IsOpenCover U) : ∃ (n : ℕ) (V : Fin n → Clopens X),
    (∀ j, ∃ i, (V j : Set X) ⊆ U i) ∧ univ ⊆ ⋃ j, (V j : Set X) := by
-- Choose an index `r x` for each point in `X` such that `∀ x, x ∈ U (r x)`.
  choose r hr using hU.exists_mem
  -- Choose a clopen neighbourhood `V x` of each `x` contained in `U (r x)`.
  choose V hV hVx hVU using fun x ↦ compact_exists_isClopen_in_isOpen (U _).isOpen (hr x)
  -- Apply compactness to extract a finite subset of the `V`s which covers `X`.
  obtain ⟨t, ht⟩ : ∃ t, univ ⊆ ⋃ i ∈ t, V i :=
    isCompact_univ.elim_finite_subcover V (fun x ↦ (hV x).2) (fun x _ ↦ mem_iUnion.mpr ⟨x, hVx x⟩)
  -- Biject it noncanonically with `Fin n` for some `n`.
  refine ⟨_, fun j ↦ ⟨_, hV (t.equivFin.symm j)⟩, fun j ↦ ⟨_, hVU _⟩, fun x hx ↦ ?_⟩
  obtain ⟨m, hm, hm'⟩ := mem_iUnion₂.mp (ht hx)
  exact Set.mem_iUnion_of_mem (t.equivFin ⟨m, hm⟩) (by simpa)

/-- Any open cover of a profinite space can be refined to a finite cover by pairwise disjoint
nonempty clopens. -/
```

-- snippet 30
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iInf (L129-L153)
lemma completelyRegularSpace_iInf {ι X : Type*} {t : ι → TopologicalSpace X}
    (ht : ∀ i, @CompletelyRegularSpace X (t i)) : @CompletelyRegularSpace X (⨅ i, t i) := by
letI := (⨅ i, t i) -- register this as default topological space to reduce `@`s
  rw [completelyRegularSpace_iff_isOpen]
  intro x K hK hxK
  simp_rw [← hK.mem_nhds_iff, nhds_iInf, mem_iInf, exists_finite_iff_finset,
    Finset.coe_sort_coe] at hxK; clear hK
  obtain ⟨I', V, hV, rfl⟩ := hxK
  simp only [mem_nhds_iff] at hV
  choose U hUV hU hxU using hV
  replace hU := fun (i : ↥I') =>
    @CompletelyRegularSpace.completely_regular_isOpen _ (t i) (ht i) x (U i) (hU i) (hxU i)
  clear hxU
  choose fs hfs hxfs hfsU using hU
  use I'.attach.sup fs
  constructorm* _ ∧ _
  · solve_by_elim [Continuous.finset_sup, continuous_iInf_dom]
  · simpa [show (0 : ↥I) = ⊥ from rfl] using hxfs
  · simp only [EqOn, Pi.one_apply, show (1 : ↥I) = ⊤ from rfl] at hfsU ⊢
    conv => equals ∀ x i, x ∈ (V i)ᶜ → ∃ b, fs b x = ⊤ => simp [Finset.sup_eq_top_iff]
    intro x i hxi
    specialize hfsU i (by tauto_set)
    exists i

set_option backward.isDefEq.respectTransparency false in
```

-- snippet 31
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_iff_isInducing_stoneCechUnit (L191-L196)
lemma completelyRegularSpace_iff_isInducing_stoneCechUnit :
    CompletelyRegularSpace X ↔ IsInducing (stoneCechUnit : X → StoneCech X) where
  mp _ := isInducing_stoneCechUnit
mpr hs := hs.completelyRegularSpace

open TopologicalSpace Cardinal in
```

-- snippet 32
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_finite_approximation_of_mem_nhds_diagonal (L140-L161)
lemma exists_finite_approximation_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal V)) :
    ∃ (n : ℕ) (g : X → Fin n) (h : Fin n → V), Continuous g ∧ ∀ x, (f x, h (g x)) ∈ S := by
obtain ⟨n, E, hEne, hES, hEuniv, hEdis⟩ :=
    exists_disjoint_nonempty_clopen_cover_of_mem_nhds_diagonal f hS
  have h_uniq (x) : ∃! i, x ∈ E i := by
    refine match mem_iUnion.mp (hEuniv <| mem_univ x) with
      | ⟨i, hi⟩ => ⟨i, hi, fun j hj ↦ hEdis.eq ?_⟩
    simpa [← Clopens.coe_disjoint, not_disjoint_iff] using ⟨x, hj, hi⟩
  choose g hg hg' using h_uniq -- for each `x`, `g x` is the unique `i` such that `x ∈ E i`
  have h_ex (i) : ∃ x, x ∈ E i := by
    simpa [← SetLike.coe_set_eq, ← nonempty_iff_ne_empty] using hEne i
  choose r hr using h_ex -- for each `i`, choose an `r i ∈ E i`
  refine ⟨n, g, f ∘ r, continuous_discrete_rng.mpr fun j ↦ ?_, fun x ↦ (hES _) _ (hg _) _ (hr _)⟩
  convert (E j).isOpen
  exact Set.ext fun x ↦ ⟨fun hj ↦ hj ▸ hg x, fun hx ↦ (hg' _ _ hx).symm⟩

/--
If `f` is a continuous map from a profinite space to a topological space with a commutative monoid
structure, then we can approximate `f` by finite products of indicator functions of clopen sets.

(Note no compatibility is assumed between the monoid structure on `V` and the topology.)
-/
```

-- snippet 33
```lean
-- Mathlib.Topology.Separation.DisjointCover.exists_open_prod_subset_of_mem_nhds_diagonal (L79-L91)
lemma exists_open_prod_subset_of_mem_nhds_diagonal (hS : S ∈ nhdsSet (diagonal X)) (x : X) :
    ∃ U : Set X, IsOpen U ∧ x ∈ U ∧ U ×ˢ U ⊆ S := by
have : S ∈ 𝓝 (x, x) := mem_nhdsSet_iff_forall.mp hS _ rfl
  obtain ⟨u, v, huo, hux, hvo, hvx, H⟩ := by rwa [mem_nhds_prod_iff'] at this
  exact ⟨_, huo.inter hvo, ⟨hux, hvx⟩, fun p hp ↦ H ⟨hp.1.1, hp.2.2⟩⟩

variable [CompactSpace X]

/-- If `S` is any neighbourhood of the diagonal in a compact topological space `X`, then there
exists a finite cover of `X` by opens `U i` such that `U i ×ˢ U i ⊆ S` for all `i`.

That the indexing set is a finset of `X` is an artifact of the proof; it could be any finite type.
-/
```

-- snippet 34
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.completelyRegularSpace_induced (L124-L128)
lemma completelyRegularSpace_induced
    {X Y : Type*} {t : TopologicalSpace Y} (ht : @CompletelyRegularSpace Y t)
    (f : X → Y) : @CompletelyRegularSpace X (t.induced f) :=
@IsInducing.completelyRegularSpace _ (t.induced f) _ t _ _ (IsInducing.induced f)
```

-- snippet 35
```lean
-- Mathlib.Topology.Separation.AlexandrovDiscrete.nhdsKer_eq_of_t1Space (L22-L24)
lemma nhdsKer_eq_of_t1Space [T1Space X] (s : Set X) : nhdsKer s = s := by
ext; simp [mem_nhdsKer_iff_specializes]
```

-- snippet 36
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.isEmbedding_stoneCechUnit (L260-L264)
lemma isEmbedding_stoneCechUnit [T35Space X] :
    IsEmbedding (stoneCechUnit : X → StoneCech X) where
  toIsInducing := isInducing_stoneCechUnit
injective := injective_stoneCechUnit_of_t35Space
```

-- snippet 37
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.CompletelyRegularSpace (L79-L83)
lemma CompletelyRegularSpace.completely_regular_isOpen [CompletelyRegularSpace X] :
    ∀ (x : X), ∀ K : Set X, IsOpen K → x ∈ K →
      ∃ f : X → I, Continuous f ∧ f x = 0 ∧ EqOn f 1 Kᶜ :=
completelyRegularSpace_iff_isOpen.mp inferInstance
```

-- snippet 38
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.injective_stoneCechUnit_of_t35Space (L253-L259)
lemma injective_stoneCechUnit_of_t35Space [T35Space X] :
    Function.Injective (stoneCechUnit : X → StoneCech X) := by
intro a b hab
  contrapose hab
  obtain ⟨f, fc, fab⟩ := separatesPoints_continuous_of_t35Space_Icc hab
  exact fun q ↦ fab (eq_if_stoneCechUnit_eq fc q)
```

-- snippet 39
```lean
-- Mathlib.Topology.Separation.Connected.IsPreconnected (L36-L41)
theorem IsPreconnected.infinite_of_nontrivial [T1Space X] {s : Set X} (h : IsPreconnected s)
    (hs : s.Nontrivial) : s.Infinite := by
refine mt (fun hf => (subsingleton_coe s).mp ?_) (not_subsingleton_iff.mpr hs)
  haveI := @Finite.instDiscreteTopology s _ _ hf.to_subtype
  exact @PreconnectedSpace.trivial_of_discrete _ _ (Subtype.preconnectedSpace h) _
```

-- snippet 40
```lean
-- Mathlib.Topology.Separation.CompletelyRegular.separatesPoints_continuous_of_t35Space_Icc (L246-L252)
lemma separatesPoints_continuous_of_t35Space_Icc [T35Space X] :
    SeparatesPoints {f : X → I | Continuous f} := by
intro x y x_ne_y
  obtain ⟨f, f_cont, f_zero, f_one⟩ :=
    CompletelyRegularSpace.completely_regular x {y} isClosed_singleton x_ne_y
  exact ⟨f, f_cont, by simp_all⟩
```
[/INST]