Skip to content

Commit 37ee77c

Browse files
committed
feat(Topology/Algebra): discrete iff finite index subgroup discrete (#29743)
Show that if G is a topological group and H is a finite-index subgroup, then H is discrete iff G is. As application, show that arithmetic subgroups of GL(2, R), which are by definition those commensurable with SL(2, Z), are discrete.
1 parent 1f0a5ce commit 37ee77c

File tree

8 files changed

+182
-16
lines changed

8 files changed

+182
-16
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6444,6 +6444,7 @@ import Mathlib.Topology.Algebra.IsOpenUnits
64446444
import Mathlib.Topology.Algebra.IsUniformGroup.Basic
64456445
import Mathlib.Topology.Algebra.IsUniformGroup.Constructions
64466446
import Mathlib.Topology.Algebra.IsUniformGroup.Defs
6447+
import Mathlib.Topology.Algebra.IsUniformGroup.DiscreteSubgroup
64476448
import Mathlib.Topology.Algebra.IsUniformGroup.Order
64486449
import Mathlib.Topology.Algebra.LinearTopology
64496450
import Mathlib.Topology.Algebra.Localization

Mathlib/Data/Set/Constructions.lean

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,9 @@ theorem mk₂ (h : ∀ ⦃s⦄, s ∈ S → ∀ ⦃t⦄, t ∈ S → s ∩ t ∈
8585
inter_mem s hs t ht := by aesop
8686

8787
end FiniteInter
88+
89+
/-- This is a hybrid of `Set.biUnion_empty` and `Finset.biUnion_empty` (the index set on the LHS is
90+
the empty finset, but `s` is a family of sets, not finsets). -/
91+
theorem Set.biUnion_empty_finset {ι X : Type*} {s : ι → Set X} :
92+
⋃ i ∈ (∅ : Finset ι), s i = ∅ := by
93+
simp only [Finset.notMem_empty, iUnion_of_empty, iUnion_empty]

Mathlib/NumberTheory/ModularForms/ArithmeticSubgroups.lean

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ Copyright (c) 2025 David Loeffler. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: David Loeffler
55
-/
6-
import Mathlib.Data.Real.Basic
7-
import Mathlib.GroupTheory.Commensurable
8-
import Mathlib.LinearAlgebra.Matrix.GeneralLinearGroup.Defs
9-
import Mathlib.Topology.Algebra.IsUniformGroup.Basic
6+
import Mathlib.Topology.Algebra.IsUniformGroup.DiscreteSubgroup
107
import Mathlib.Topology.Algebra.Ring.Real
118
import Mathlib.Topology.Instances.Matrix
129
import Mathlib.Topology.MetricSpace.Isometry
@@ -114,3 +111,9 @@ lemma isClosedEmbedding_mapGLInt : Topology.IsClosedEmbedding (mapGL ℝ : SL n
114111
⟨isEmbedding_mapGL (Isometry.isEmbedding fun _ _ ↦ rfl), (mapGL ℝ).range.isClosed_of_discrete⟩
115112

116113
end Matrix.SpecialLinearGroup
114+
115+
/-- Arithmetic subgroups of `GL(2, ℝ)` are discrete. -/
116+
instance Subgroup.IsArithmetic.discreteTopology {𝒢 : Subgroup (GL (Fin 2) ℝ)} [IsArithmetic 𝒢] :
117+
DiscreteTopology 𝒢 := by
118+
rw [is_commensurable.discreteTopology_iff]
119+
infer_instance

Mathlib/Topology/Algebra/ContinuousMonoidHom.lean

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,14 @@ def symm (cme : M ≃ₜ* N) : N ≃ₜ* M :=
419419
{ cme.toMulEquiv.symm with
420420
continuous_toFun := cme.continuous_invFun
421421
continuous_invFun := cme.continuous_toFun }
422+
423+
/-- See Note [custom simps projection] -/
424+
@[to_additive /-- See Note [custom simps projection] -/]
425+
def Simps.symm_apply [Mul G] [Mul H] (e : G ≃ₜ* H) : H → G :=
426+
e.symm
427+
422428
initialize_simps_projections ContinuousMulEquiv (toFun → apply, invFun → symm_apply)
429+
423430
initialize_simps_projections ContinuousAddEquiv (toFun → apply, invFun → symm_apply)
424431

425432
@[to_additive]
@@ -545,6 +552,38 @@ end unique
545552

546553
end ContinuousMulEquiv
547554

555+
namespace MulEquiv
556+
557+
variable {G H} [Mul G] [Mul H] (e : G ≃* H) (he : ∀ s, IsOpen (e ⁻¹' s) ↔ IsOpen s)
558+
include he
559+
560+
/-- A `MulEquiv` that respects open sets is a `ContinuousMulEquiv`. -/
561+
@[to_additive (attr := simps apply symm_apply)
562+
/-- An `AddEquiv` that respects open sets is a `ContinuousAddEquiv`. -/]
563+
def toContinuousMulEquiv : G ≃ₜ* H where
564+
toFun := e
565+
invFun := e.symm
566+
__ := e
567+
__ := e.toEquiv.toHomeomorph he
568+
569+
variable {e}
570+
571+
@[to_additive, simp]
572+
lemma toMulEquiv_toContinuousMulEquiv : (e.toContinuousMulEquiv he : G ≃* H) = e :=
573+
rfl
574+
575+
@[to_additive, simp] lemma toHomeomorph_toContinuousMulEquiv :
576+
(e.toContinuousMulEquiv he : G ≃ₜ H) = e.toHomeomorph he :=
577+
rfl
578+
579+
@[to_additive]
580+
lemma symm_toContinuousMulEquiv :
581+
(e.toContinuousMulEquiv he).symm = e.symm.toContinuousMulEquiv
582+
(fun s ↦ by convert (he _).symm; exact (e.preimage_symm_preimage s).symm) :=
583+
rfl
584+
585+
end MulEquiv
586+
548587
end
549588

550589
end
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/-
2+
Copyright (c) 2025 David Loeffler. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: David Loeffler
5+
-/
6+
7+
import Mathlib.GroupTheory.Commensurable
8+
import Mathlib.Topology.Algebra.ContinuousMonoidHom
9+
import Mathlib.Topology.Algebra.Group.ClosedSubgroup
10+
import Mathlib.Topology.Algebra.IsUniformGroup.Basic
11+
12+
/-!
13+
# Discrete subgroups of topological groups
14+
15+
Note that the instance `Subgroup.isClosed_of_discrete` does not live here, in order that it can
16+
be used in other files without requiring lots of group-theoretic imports.
17+
-/
18+
19+
open Filter Topology Uniformity
20+
21+
variable {G : Type*} [Group G] [TopologicalSpace G]
22+
23+
/-- If `G` has a topology, and `H ≤ K` are subgroups, then `H` as a subgroup of `K` is isomorphic,
24+
as a topological group, to `H` as a subgroup of `G`. This is `subgroupOfEquivOfLe` upgraded to a
25+
`ContinuousMulEquiv`. -/
26+
@[to_additive (attr := simps! apply) /-- If `G` has a topology, and `H ≤ K` are
27+
subgroups, then `H` as a subgroup of `K` is isomorphic, as a topological group, to `H` as a subgroup
28+
of `G`. This is `addSubgroupOfEquivOfLe` upgraded to a `ContinuousAddEquiv`.-/]
29+
def Subgroup.subgroupOfContinuousMulEquivOfLe {H K : Subgroup G} (hHK : H ≤ K) :
30+
(H.subgroupOf K) ≃ₜ* H :=
31+
(subgroupOfEquivOfLe hHK).toContinuousMulEquiv (by
32+
simp only [subgroupOfEquivOfLe, Topology.IsInducing.subtypeVal.isOpen_iff,
33+
exists_exists_and_eq_and]
34+
simpa [Set.ext_iff] using fun s ↦ exists_congr
35+
fun t ↦ and_congr_right fun _ ↦ ⟨fun aux g hgh ↦ aux g (hHK hgh) hgh, by grind⟩)
36+
37+
@[to_additive (attr := simp)]
38+
lemma Subgroup.subgroupOfContinuousMulEquivOfLe_symm_apply
39+
{H K : Subgroup G} (hHK : H ≤ K) (g : H) :
40+
(subgroupOfContinuousMulEquivOfLe hHK).symm g = ⟨⟨g.1, hHK g.2⟩, g.2⟩ :=
41+
rfl
42+
43+
@[to_additive (attr := simp)]
44+
lemma Subgroup.subgroupOfContinuousMulEquivOfLe_toMulEquiv {H K : Subgroup G} (hHK : H ≤ K) :
45+
(subgroupOfContinuousMulEquivOfLe hHK : H.subgroupOf K ≃* H) = subgroupOfEquivOfLe hHK := by
46+
rfl
47+
48+
variable [IsTopologicalGroup G] [T2Space G]
49+
50+
/-- If `G` is a topological group and `H` a finite-index subgroup, then `G` is topologically
51+
discrete iff `H` is. -/
52+
@[to_additive]
53+
lemma Subgroup.discreteTopology_iff_of_finiteIndex {H : Subgroup G} [H.FiniteIndex] :
54+
DiscreteTopology H ↔ DiscreteTopology G := by
55+
refine ⟨fun hH ↦ ?_, fun hG ↦ inferInstance⟩
56+
suffices IsOpen (H : Set G) by
57+
rw [discreteTopology_iff_isOpen_singleton_one, isOpen_singleton_iff_nhds_eq_pure,
58+
← H.coe_one, ← this.isOpenEmbedding_subtypeVal.map_nhds_eq, nhds_discrete, map_pure]
59+
exact H.isOpen_of_isClosed_of_finiteIndex Subgroup.isClosed_of_discrete
60+
61+
@[to_additive]
62+
lemma Subgroup.discreteTopology_iff_of_isFiniteRelIndex {H K : Subgroup G} (hHK : H ≤ K)
63+
[IsFiniteRelIndex H K] : DiscreteTopology H ↔ DiscreteTopology K := by
64+
haveI : (H.subgroupOf K).FiniteIndex := IsFiniteRelIndex.to_finiteIndex_subgroupOf
65+
rw [← (subgroupOfContinuousMulEquivOfLe hHK).discreteTopology_iff,
66+
discreteTopology_iff_of_finiteIndex]
67+
68+
@[to_additive]
69+
lemma Subgroup.Commensurable.discreteTopology_iff
70+
{G : Type*} [Group G] [TopologicalSpace G] [IsTopologicalGroup G] [T2Space G]
71+
{H K : Subgroup G} (h : Commensurable H K) :
72+
DiscreteTopology H ↔ DiscreteTopology K :=
73+
calc DiscreteTopology H ↔ DiscreteTopology ↑(H ⊓ K) :=
74+
haveI : IsFiniteRelIndex (H ⊓ K) H := ⟨Subgroup.inf_relIndex_left H K ▸ h.2
75+
(Subgroup.discreteTopology_iff_of_isFiniteRelIndex inf_le_left).symm
76+
_ ↔ DiscreteTopology K :=
77+
haveI : IsFiniteRelIndex (H ⊓ K) K := ⟨Subgroup.inf_relIndex_right H K ▸ h.1
78+
Subgroup.discreteTopology_iff_of_isFiniteRelIndex inf_le_right

Mathlib/Topology/Constructions.lean

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,6 @@ theorem nhds_ne_subtype_neBot_iff {S : Set X} {x : S} :
237237
(𝓝[≠] x).NeBot ↔ (𝓝[≠] (x : X) ⊓ 𝓟 S).NeBot := by
238238
rw [neBot_iff, neBot_iff, not_iff_not, nhds_ne_subtype_eq_bot_iff]
239239

240-
theorem discreteTopology_subtype_iff {S : Set X} :
241-
DiscreteTopology S ↔ ∀ x ∈ S, 𝓝[≠] x ⊓ 𝓟 S = ⊥ := by
242-
simp_rw [discreteTopology_iff_nhds_ne, SetCoe.forall', nhds_ne_subtype_eq_bot_iff]
243-
244240
end Top
245241

246242
/-- A type synonym equipped with the topology whose open sets are the empty set and the sets with

Mathlib/Topology/DiscreteSubset.lean

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,26 @@ This is the filter of all open codiscrete sets within S. We also define `Filter.
4040

4141
open Set Filter Function Topology
4242

43-
variable {X Y : Type*} [TopologicalSpace Y] {f : X → Y}
43+
variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] {f : X → Y}
44+
45+
theorem discreteTopology_subtype_iff {S : Set Y} :
46+
DiscreteTopology S ↔ ∀ x ∈ S, 𝓝[≠] x ⊓ 𝓟 S = ⊥ := by
47+
simp_rw [discreteTopology_iff_nhds_ne, SetCoe.forall', nhds_ne_subtype_eq_bot_iff]
48+
49+
lemma discreteTopology_subtype_iff' {S : Set Y} :
50+
DiscreteTopology S ↔ ∀ y ∈ S, ∃ U : Set Y, IsOpen U ∧ U ∩ S = {y} := by
51+
simp [discreteTopology_iff_isOpen_singleton, isOpen_induced_iff, Set.ext_iff]
52+
grind
4453

4554
section cofinite_cocompact
4655

56+
omit [TopologicalSpace X] in
4757
lemma tendsto_cofinite_cocompact_iff :
4858
Tendsto f cofinite (cocompact _) ↔ ∀ K, IsCompact K → Set.Finite (f ⁻¹' K) := by
4959
rw [hasBasis_cocompact.tendsto_right_iff]
5060
refine forall₂_congr (fun K _ ↦ ?_)
5161
simp only [mem_compl_iff, eventually_cofinite, not_not, preimage]
5262

53-
variable [TopologicalSpace X]
54-
5563
lemma Continuous.discrete_of_tendsto_cofinite_cocompact [T1Space X] [WeaklyLocallyCompactSpace Y]
5664
(hf' : Continuous f) (hf : Tendsto f cofinite (cocompact _)) :
5765
DiscreteTopology X := by
@@ -83,8 +91,6 @@ end cofinite_cocompact
8391

8492
section codiscrete_filter
8593

86-
variable [TopologicalSpace X]
87-
8894
/-- Criterion for a subset `S ⊆ X` to be closed and discrete in terms of the punctured
8995
neighbourhood filter at an arbitrary point of `X`. (Compare `discreteTopology_subtype_iff`.) -/
9096
theorem isClosed_and_discrete_iff {S : Set X} :
@@ -240,3 +246,33 @@ lemma mem_codiscrete_subtype_iff_mem_codiscreteWithin {S : Set X} {U : Set S} :
240246
continuous_subtype_val.continuousWithinAt <| eventually_mem_nhdsWithin.mono (by simp)
241247

242248
end codiscrete_filter
249+
250+
section discrete_union
251+
252+
lemma compl_mem_codiscrete_iff {S : Set X} :
253+
Sᶜ ∈ codiscrete X ↔ IsClosed S ∧ DiscreteTopology ↑S := by
254+
rw [mem_codiscrete, compl_compl, isClosed_and_discrete_iff]
255+
256+
/-- The union of two discrete closed subsets is discrete. -/
257+
theorem discreteTopology_union {S T : Set X} (hs : DiscreteTopology S) (ht : DiscreteTopology T)
258+
(hs' : IsClosed S) (ht' : IsClosed T) : DiscreteTopology ↑(S ∪ T) := by
259+
suffices (S ∪ T)ᶜ ∈ codiscrete X from compl_mem_codiscrete_iff.mp this |>.2
260+
have hS : Sᶜ ∈ codiscrete X := by simpa [compl_mem_codiscrete_iff] using ⟨hs', hs⟩
261+
have hT : Tᶜ ∈ codiscrete X := by simpa [compl_mem_codiscrete_iff] using ⟨ht', ht⟩
262+
simpa using inter_mem hS hT
263+
264+
/-- The union of finitely many discrete closed subsets is discrete. -/
265+
theorem discreteTopology_biUnion_finset {ι : Type*} {I : Finset ι} {s : ι → Set X}
266+
(hs : ∀ i ∈ I, DiscreteTopology (s i)) (hs' : ∀ i ∈ I, IsClosed (s i)) :
267+
DiscreteTopology (⋃ i ∈ I, s i) := by
268+
suffices (⋃ i ∈ I, s i)ᶜ ∈ codiscrete X from (compl_mem_codiscrete_iff.mp this).2
269+
simpa [biInter_finset_mem I] using fun i hi ↦ compl_mem_codiscrete_iff.mpr ⟨hs' i hi, hs i hi⟩
270+
271+
/-- The union of finitely many discrete closed subsets is discrete. -/
272+
theorem discreteTopology_iUnion_fintype {ι : Type*} [Fintype ι] {s : ι → Set X}
273+
(hs : ∀ i, DiscreteTopology (s i)) (hs' : ∀ i, IsClosed (s i)) :
274+
DiscreteTopology (⋃ i, s i) := by
275+
convert discreteTopology_biUnion_finset (I := .univ) (fun i _ ↦ hs i) (fun i _ ↦ hs' i) <;>
276+
simp
277+
278+
end discrete_union

Mathlib/Topology/Homeomorph/Defs.lean

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ theorem symm_bijective : Function.Bijective (Homeomorph.symm : (X ≃ₜ Y) →
8484
def Simps.symm_apply (h : X ≃ₜ Y) : Y → X :=
8585
h.symm
8686

87-
initialize_simps_projections Homeomorph (toFun → apply, invFun → symm_apply)
87+
initialize_simps_projections Homeomorph (toFun → apply, invFun → symm_apply, as_prefix toEquiv)
8888

8989
@[simp]
9090
theorem coe_toEquiv (h : X ≃ₜ Y) : ⇑h.toEquiv = h :=
@@ -336,15 +336,19 @@ def toHomeomorph (e : X ≃ Y) (he : ∀ s, IsOpen (e ⁻¹' s) ↔ IsOpen s) :
336336
continuous_toFun := continuous_def.2 fun _ ↦ (he _).2
337337
continuous_invFun := continuous_def.2 fun s ↦ by convert (he _).1; simp
338338

339+
@[deprecated (since := "2025-10-09")] alias toHomeomorph_toEquiv := toEquiv_toHomeomorph
340+
339341
@[simp] lemma coe_toHomeomorph (e : X ≃ Y) (he) : ⇑(e.toHomeomorph he) = e := rfl
340342
lemma toHomeomorph_apply (e : X ≃ Y) (he) (x : X) : e.toHomeomorph he x = e x := rfl
341343

342344
@[simp] lemma toHomeomorph_refl :
343345
(Equiv.refl X).toHomeomorph (fun _s ↦ Iff.rfl) = Homeomorph.refl _ := rfl
344346

345-
@[simp] lemma toHomeomorph_symm (e : X ≃ Y) (he) :
347+
@[simp] lemma symm_toHomeomorph (e : X ≃ Y) (he) :
346348
(e.toHomeomorph he).symm = e.symm.toHomeomorph fun s ↦ by convert (he _).symm; simp := rfl
347349

350+
@[deprecated (since := "2025-10-09")] alias toHomeomorph_symm := symm_toHomeomorph
351+
348352
lemma toHomeomorph_trans (e : X ≃ Y) (f : Y ≃ Z) (he hf) :
349353
(e.trans f).toHomeomorph (fun _s ↦ (he _).trans (hf _)) =
350354
(e.toHomeomorph he).trans (f.toHomeomorph hf) := rfl
@@ -371,8 +375,11 @@ def toHomeomorphOfContinuousOpen (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsO
371375
@[deprecated (since := "2025-04-16")]
372376
alias _root_.Homeomorph.homeomorphOfContinuousOpen := toHomeomorphOfContinuousOpen
373377

378+
@[deprecated (since := "2025-10-09")] alias toHomeomorphOfContinuousOpen_toEquiv :=
379+
toEquiv_toHomeomorphOfContinuousOpen
380+
374381
@[deprecated (since := "2025-04-16")]
375-
alias _root_.Homeomorph.homeomorphOfContinuousOpen_toEquiv := toHomeomorphOfContinuousOpen_toEquiv
382+
alias _root_.Homeomorph.homeomorphOfContinuousOpen_toEquiv := toEquiv_toHomeomorphOfContinuousOpen
376383

377384
@[simp]
378385
theorem toHomeomorphOfContinuousOpen_apply (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpenMap e) :

0 commit comments

Comments
 (0)