Skip to content

Commit ed3702c

Browse files
committed
feat: Finite product of Alexandrov-discrete spaces is Alexandrov-discrete (#27018)
1 parent 69c685f commit ed3702c

File tree

3 files changed

+74
-6
lines changed

3 files changed

+74
-6
lines changed

Mathlib/Order/Filter/Ker.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,13 @@ theorem ker_sSup (S : Set (Filter α)) : ker (sSup S) = ⋃ f ∈ S, ker f := by
6868
theorem ker_sup (f g : Filter α) : ker (f ⊔ g) = ker f ∪ ker g := by
6969
rw [← sSup_pair, ker_sSup, biUnion_pair]
7070

71+
@[simp]
72+
lemma ker_prod (f : Filter α) (g : Filter β) : ker (f ×ˢ g) = ker f ×ˢ ker g := by
73+
simp [Set.prod_eq, Filter.prod_eq_inf]
74+
75+
@[simp]
76+
lemma ker_pi {ι : Type*} {α : ι → Type*} (f : (i : ι) → Filter (α i)) :
77+
ker (Filter.pi f) = univ.pi (fun i => ker (f i)) := by
78+
simp [Set.pi_def, Filter.pi]
79+
7180
end Filter

Mathlib/Topology/AlexandrovDiscrete.lean

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ minimal neighborhood, which we call the *neighborhoods kernel* of the set.
2121
2222
* `AlexandrovDiscrete`: Prop-valued typeclass for a topological space to be Alexandrov-discrete
2323
24-
## TODO
25-
26-
Finite product of Alexandrov-discrete spaces is Alexandrov-discrete.
27-
2824
## Tags
2925
3026
Alexandroff, discrete, finitely generated, fg space
@@ -34,6 +30,7 @@ open Filter Set TopologicalSpace Topology
3430

3531
/-- A topological space is **Alexandrov-discrete** or **finitely generated** if the intersection of
3632
a family of open sets is open. -/
33+
@[mk_iff]
3734
class AlexandrovDiscrete (α : Type*) [TopologicalSpace α] : Prop where
3835
/-- The intersection of a family of open sets is an open set. Use `isOpen_sInter` in the root
3936
namespace instead. -/
@@ -43,6 +40,12 @@ variable {ι : Sort*} {κ : ι → Sort*} {α β : Type*}
4340
section
4441
variable [TopologicalSpace α] [TopologicalSpace β]
4542

43+
lemma alexandrovDiscrete_iff_isClosed :
44+
AlexandrovDiscrete α ↔ ∀ S : Set (Set α), (∀ s ∈ S, IsClosed s) → IsClosed (⋃₀ S) := by
45+
conv_lhs => tactic =>
46+
simp_rw +singlePass [alexandrovDiscrete_iff, compl_surjective.image_surjective.forall,
47+
forall_mem_image, ← compl_sUnion, isOpen_compl_iff]
48+
4649
instance DiscreteTopology.toAlexandrovDiscrete [DiscreteTopology α] : AlexandrovDiscrete α where
4750
isOpen_sInter _ _ := isOpen_discrete _
4851

@@ -61,8 +64,8 @@ lemma isOpen_iInter₂ {f : ∀ i, κ i → Set α} (hf : ∀ i j, IsOpen (f i j
6164
IsOpen (⋂ i, ⋂ j, f i j) :=
6265
isOpen_iInter fun _ ↦ isOpen_iInter <| hf _
6366

64-
lemma isClosed_sUnion (hS : ∀ s ∈ S, IsClosed s) : IsClosed (⋃₀ S) := by
65-
simp only [← isOpen_compl_iff, compl_sUnion] at hS ⊢; exact isOpen_sInter <| forall_mem_image.2 hS
67+
lemma isClosed_sUnion (hS : ∀ s ∈ S, IsClosed s) : IsClosed (⋃₀ S) :=
68+
alexandrovDiscrete_iff_isClosed.mp inferInstance S hS
6669

6770
lemma isClosed_iUnion (hf : ∀ i, IsClosed (f i)) : IsClosed (⋃ i, f i) :=
6871
isClosed_sUnion <| forall_mem_range.2 hf
@@ -196,6 +199,18 @@ lemma isOpen_iff_forall_specializes : IsOpen s ↔ ∀ x y, x ⤳ y → y ∈ s
196199
simp only [← nhdsKer_subset_iff_isOpen, Set.subset_def, mem_nhdsKer_iff_specializes, exists_imp,
197200
and_imp, @forall_swap (_ ⤳ _)]
198201

202+
omit [AlexandrovDiscrete α] in
203+
lemma alexandrovDiscrete_iff_nhds : AlexandrovDiscrete α ↔ (∀ a : α, 𝓝 a = 𝓟 (nhdsKer {a})) where
204+
mp _ a := principal_nhdsKer_singleton a |>.symm
205+
mpr hα := by
206+
simp only [alexandrovDiscrete_iff_isClosed, isClosed_iff_clusterPt, ClusterPt, funext hα,
207+
inf_principal, principal_neBot_iff]
208+
intro S hS a ha
209+
rw [sUnion_eq_biUnion, inter_iUnion₂, nonempty_biUnion] at ha
210+
obtain ⟨s, hs, has⟩ := ha
211+
specialize hS s hs a has
212+
exact mem_sUnion_of_mem hS hs
213+
199214
lemma alexandrovDiscrete_coinduced {β : Type*} {f : α → β} :
200215
@AlexandrovDiscrete β (coinduced f ‹_›) :=
201216
@AlexandrovDiscrete.mk β (coinduced f ‹_›) fun S hS ↦ by
@@ -222,4 +237,14 @@ instance Sigma.instAlexandrovDiscrete {ι : Type*} {X : ι → Type*} [∀ i, To
222237
[∀ i, AlexandrovDiscrete (X i)] : AlexandrovDiscrete (Σ i, X i) :=
223238
alexandrovDiscrete_iSup fun _ ↦ alexandrovDiscrete_coinduced
224239

240+
instance Prod.instAlexandrovDiscrete : AlexandrovDiscrete (α × β) := by
241+
simp_rw [alexandrovDiscrete_iff_nhds, Prod.forall, nhds_prod_eq, ← principal_nhdsKer_singleton,
242+
prod_principal_principal, nhdsKer_pair, forall_true_iff]
243+
244+
instance Pi.instAlexandrovDiscreteOfFinite {ι : Type*} [Finite ι] {X : ι → Type*}
245+
[Π i, TopologicalSpace (X i)] [∀ i, AlexandrovDiscrete (X i)] :
246+
AlexandrovDiscrete (Π i, X i) := by
247+
simp_rw [alexandrovDiscrete_iff_nhds, nhds_pi, ← principal_nhdsKer_singleton,
248+
pi_principal, nhdsKer_singleton_pi, forall_true_iff]
249+
225250
end

Mathlib/Topology/NhdsKer.lean

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ theorem nhdsKer_iUnion (s : ι → Set X) : nhdsKer (⋃ i, s i) = ⋃ i, nhdsKe
7171

7272
@[deprecated (since := "2025-07-09")] alias exterior_iUnion := nhdsKer_iUnion
7373

74+
theorem nhdsKer_biUnion {ι : Type*} (s : Set ι) (t : ι → Set X) :
75+
nhdsKer (⋃ i ∈ s, t i) = ⋃ i ∈ s, nhdsKer (t i) := by
76+
simp only [nhdsKer_iUnion]
77+
7478
@[simp]
7579
theorem nhdsKer_union (s t : Set X) : nhdsKer (s ∪ t) = nhdsKer s ∪ nhdsKer t := by
7680
simp only [nhdsKer, nhdsSet_union, ker_sup]
@@ -160,3 +164,33 @@ theorem nhdsKer_sInter_subset {s : Set (Set X)} : nhdsKer (⋂₀ s) ⊆ ⋂ x
160164
simp only [nhdsKer_eq_nhdsKer_iff_nhdsSet, nhdsSet_nhdsKer]
161165

162166
@[deprecated (since := "2025-07-09")] alias exterior_exterior := nhdsKer_nhdsKer
167+
168+
lemma nhdsKer_pair {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y]
169+
(x : X) (y : Y) : nhdsKer {(x, y)} = nhdsKer {x} ×ˢ nhdsKer {y} := by
170+
simp_rw [nhdsKer_singleton_eq_ker_nhds, nhds_prod_eq, ker_prod]
171+
172+
lemma nhdsKer_prod {Y : Type*} [TopologicalSpace Y] (s : Set X) (t : Set Y) :
173+
nhdsKer (s ×ˢ t) = nhdsKer s ×ˢ nhdsKer t := calc
174+
_ = ⋃ (p ∈ s ×ˢ t), nhdsKer {p} := by
175+
conv_lhs => rw [← biUnion_of_singleton (s ×ˢ t), nhdsKer_biUnion]
176+
_ = ⋃ (p ∈ s ×ˢ t), nhdsKer {p.1} ×ˢ nhdsKer {p.2} := by
177+
congr! with ⟨x, y⟩ _; rw [nhdsKer_pair]
178+
_ = (⋃ x ∈ s, nhdsKer {x}) ×ˢ (⋃ y ∈ t, nhdsKer {y}) :=
179+
biUnion_prod s t (fun x => nhdsKer {x}) (fun y => nhdsKer {y})
180+
_ = nhdsKer s ×ˢ nhdsKer t := by
181+
simp_rw [← nhdsKer_biUnion, biUnion_of_singleton]
182+
183+
lemma nhdsKer_singleton_pi {ι : Type*} {X : ι → Type*} [Π (i : ι), TopologicalSpace (X i)]
184+
(p : Π (i : ι), X i) : nhdsKer {p} = univ.pi (fun i => nhdsKer {p i}) := by
185+
simp_rw [nhdsKer_singleton_eq_ker_nhds, nhds_pi, ker_pi]
186+
187+
lemma nhdsKer_pi {ι : Type*} {X : ι → Type*} [Π (i : ι), TopologicalSpace (X i)]
188+
(s : Π (i : ι), Set (X i)) : nhdsKer (univ.pi s) = univ.pi (fun i => nhdsKer (s i)) := calc
189+
_ = ⋃ (p ∈ univ.pi s), nhdsKer {p} := by
190+
conv_lhs => rw [← biUnion_of_singleton (univ.pi s), nhdsKer_biUnion]
191+
_ = ⋃ (p ∈ univ.pi s), univ.pi fun i => nhdsKer {p i} := by
192+
congr! with p _; rw [nhdsKer_singleton_pi]
193+
_ = univ.pi fun i => ⋃ x ∈ s i, nhdsKer {x} :=
194+
biUnion_univ_pi s fun i x => nhdsKer {x}
195+
_ = univ.pi (fun i => nhdsKer (s i)) := by
196+
simp_rw [← nhdsKer_biUnion, biUnion_of_singleton]

0 commit comments

Comments
 (0)