Skip to content

Commit 18978c4

Browse files
committed
feat(Algebra): saturation of a submonoid (leanprover-community#31132)
This PR defines the saturation of a submonoid and the type of saturated submonoids. It is used for the context of localisations. Caveat: there is a similarly named predicate called `AddSubgroup.Saturated`. Zulip: * [mathlib4 > saturation of a submonoid](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/saturation.20of.20a.20submonoid/with/548242862) * [#Is there code for X? > Closure of Submonoid in CommMonoids](https://leanprover.zulipchat.com/#narrow/channel/217875-Is-there-code-for-X.3F/topic/Closure.20of.20Submonoid.20in.20CommMonoids/near/419087778)
1 parent ad4f601 commit 18978c4

3 files changed

Lines changed: 375 additions & 28 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ public import Mathlib.Algebra.Group.Submonoid.MulAction
458458
public import Mathlib.Algebra.Group.Submonoid.MulOpposite
459459
public import Mathlib.Algebra.Group.Submonoid.Operations
460460
public import Mathlib.Algebra.Group.Submonoid.Pointwise
461+
public import Mathlib.Algebra.Group.Submonoid.Saturation
461462
public import Mathlib.Algebra.Group.Submonoid.Units
462463
public import Mathlib.Algebra.Group.Subsemigroup.Basic
463464
public import Mathlib.Algebra.Group.Subsemigroup.Defs
Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
/-
2+
Copyright (c) 2025 Kenny Lau. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kenny Lau
5+
-/
6+
module
7+
8+
public import Mathlib.Algebra.Divisibility.Basic
9+
public import Mathlib.Algebra.Group.Submonoid.Basic
10+
public import Mathlib.Order.ConditionallyCompleteLattice.Basic
11+
public import Mathlib.Order.OmegaCompletePartialOrder
12+
13+
/-! # Saturation of a submonoid
14+
15+
We define a submonoid `s` to be saturated if `x * y ∈ s → x ∈ s ∧ y ∈ s`. The type of all
16+
saturated submonoids forms a complete lattice. For a given submonoid `s` we construct the saturation
17+
of `s` as the smallest saturated submonoid containing `s`, which when the underlying type is a
18+
commutative monoid, is given by the formula `{x : M | ∃ y : M, x * y ∈ s}`.
19+
20+
Saturated submonoids are used in the context of localisations.
21+
22+
We also define the type of saturated submonoids, and endow on it the structure of a complete
23+
lattice.
24+
25+
## Main Definitions
26+
27+
* `Submonoid.MulSaturated`: the condition `x * y ∈ s ↔ x ∈ s ∧ y ∈ s`. Not to be confused with
28+
`Submonoid.PowSaturated`.
29+
* `SaturatedSubmonoid`: the type of `Submonoid` satisfying `MulSaturated`. It is a complete lattice.
30+
* `Submonoid.saturation`: the smallest saturated submonoid containing a given submonoid.
31+
32+
-/
33+
34+
@[expose] public section
35+
36+
namespace Submonoid
37+
38+
/-- Given a submonoid `s` of `M`, we say that `s` is **saturated** if it satisfies
39+
`x * y ∈ s → x ∈ s ∧ y ∈ s`.
40+
41+
It is called `MulSaturated` here to be distinguished from `Submonoid.PowSaturated` or
42+
`AddSubmonoid.NSMulSaturated`, which is also called "saturated" in the literature. -/
43+
@[to_additive
44+
/-- Given an additive submonoid `s` of `M`, we say that `s` is **saturated** if it satisfies
45+
`x + y ∈ s → x ∈ s ∧ y ∈ s`.
46+
47+
It is called `AddSaturated` here to be distinguished from `Submonoid.PowSaturated` or
48+
`AddSubmonoid.NSMulSaturated`, which is also called "saturated" in the literature. -/]
49+
def MulSaturated {M : Type*} [MulOneClass M] (s : Submonoid M) : Prop :=
50+
∀ ⦃x y⦄, x * y ∈ s → x ∈ s ∧ y ∈ s
51+
52+
namespace MulSaturated
53+
variable {M : Type*} [MulOneClass M] {s s₁ s₂ : Submonoid M}
54+
(h : s.MulSaturated) (h₁ : s₁.MulSaturated) (h₂ : s₂.MulSaturated)
55+
56+
include h in
57+
@[to_additive]
58+
theorem mul_mem_iff {x y : M} : x * y ∈ s ↔ x ∈ s ∧ y ∈ s :=
59+
⟨@h _ _, and_imp.mpr mul_mem⟩
60+
61+
@[to_additive]
62+
theorem top : MulSaturated (⊤ : Submonoid M) := fun _ _ _ ↦ ⟨trivial, trivial⟩
63+
64+
include h₁ h₂ in
65+
@[to_additive]
66+
theorem inf : MulSaturated (s₁ ⊓ s₂) :=
67+
fun _ _ hxy ↦ ⟨⟨(h₁ hxy.1).1, (h₂ hxy.2).1⟩, (h₁ hxy.1).2, (h₂ hxy.2).2
68+
69+
@[to_additive]
70+
theorem sInf {f : Set (Submonoid M)} (hf : ∀ s ∈ f, s.MulSaturated) :
71+
(sInf f).MulSaturated := fun _ _ hxy ↦ by
72+
simp_rw [mem_sInf] at hxy ⊢
73+
exact ⟨fun s hs ↦ (hf s hs <| hxy s hs).1, fun s hs ↦ (hf s hs <| hxy s hs).2
74+
75+
@[to_additive]
76+
theorem iInf {ι : Sort*} {f : ι → Submonoid M} (hf : ∀ i, (f i).MulSaturated) :
77+
(iInf f).MulSaturated :=
78+
sInf <| Set.forall_mem_range.mpr hf
79+
80+
/-- If `M` is commutative, we only need to check the left condition `x ∈ s`. -/
81+
@[to_additive /-- If `M` is commutative, we only need to check the left condition `x ∈ s`. -/]
82+
theorem of_left {M : Type*} [CommMonoid M] {s : Submonoid M}
83+
(h : ∀ ⦃x y⦄, x * y ∈ s → x ∈ s) : s.MulSaturated :=
84+
fun x y hxy ↦ ⟨h hxy, h <| mul_comm x y ▸ hxy⟩
85+
86+
/-- If `M` is commutative, we only need to check the right condition `y ∈ s`. -/
87+
@[to_additive /-- If `M` is commutative, we only need to check the right condition `y ∈ s`. -/]
88+
theorem of_right {M : Type*} [CommMonoid M] {s : Submonoid M}
89+
(h : ∀ ⦃x y⦄, x * y ∈ s → y ∈ s) : s.MulSaturated :=
90+
of_left fun x y ↦ mul_comm x y ▸ @h y x
91+
92+
end MulSaturated
93+
94+
end Submonoid
95+
96+
-- automatic generation failed
97+
/-- A saturated additive submonoid is a submonoid `s` that satisfies `x + y ∈ s → x ∈ s ∧ y ∈ s`. -/
98+
structure SaturatedAddSubmonoid (M : Type*) [AddZeroClass M] extends AddSubmonoid M where
99+
addSaturated : toAddSubmonoid.AddSaturated
100+
101+
/-- A saturated submonoid is a submonoid `s` that satisfies `x * y ∈ s → x ∈ s ∧ y ∈ s`. -/
102+
@[to_additive] structure SaturatedSubmonoid (M : Type*) [MulOneClass M] extends Submonoid M where
103+
mulSaturated : toSubmonoid.MulSaturated
104+
105+
namespace SaturatedSubmonoid
106+
variable {M : Type*} [MulOneClass M]
107+
108+
attribute [simp] mulSaturated SaturatedAddSubmonoid.addSaturated
109+
110+
@[to_additive]
111+
theorem toSubmonoid_injective : (toSubmonoid (M := M)).Injective :=
112+
fun ⟨s₁, h₁⟩ ⟨s₂, h₂⟩ eq ↦ by congr
113+
114+
@[to_additive (attr := ext)]
115+
lemma ext {s₁ s₂ : SaturatedSubmonoid M} (h : s₁.toSubmonoid = s₂.toSubmonoid) : s₁ = s₂ :=
116+
toSubmonoid_injective h
117+
118+
variable (M) in
119+
@[to_additive]
120+
instance : SetLike (SaturatedSubmonoid M) M where
121+
coe := (·.carrier)
122+
coe_injective' _ _ h := toSubmonoid_injective <| SetLike.coe_injective h
123+
124+
@[to_additive]
125+
instance : PartialOrder (SaturatedSubmonoid M) := .ofSetLike ..
126+
127+
@[to_additive]
128+
lemma ext' {s₁ s₂ : SaturatedSubmonoid M} (h : ∀ x, x ∈ s₁ ↔ x ∈ s₂) : s₁ = s₂ :=
129+
SetLike.ext h
130+
131+
variable (M) in
132+
@[to_additive]
133+
instance : SubmonoidClass (SaturatedSubmonoid M) M where
134+
mul_mem {s} := s.mul_mem
135+
one_mem {s} := s.one_mem
136+
137+
@[to_additive (attr := simp)]
138+
lemma mem_toSubmonoid {s : SaturatedSubmonoid M} {x : M} : x ∈ s.toSubmonoid ↔ x ∈ s :=
139+
Iff.rfl
140+
141+
@[to_additive]
142+
instance : Top (SaturatedSubmonoid M) where
143+
top := { (⊤ : Submonoid M) with mulSaturated := .top }
144+
145+
@[to_additive (attr := simp)]
146+
theorem mem_top {x : M} : x ∈ (⊤ : SaturatedSubmonoid M) := trivial
147+
148+
variable (M) in
149+
@[to_additive]
150+
instance : Min (SaturatedSubmonoid M) where
151+
min s₁ s₂ := { s₁.toSubmonoid ⊓ s₂.toSubmonoid with mulSaturated := .inf s₁.2 s₂.2 }
152+
153+
variable (M) in
154+
@[to_additive]
155+
instance : InfSet (SaturatedSubmonoid M) where
156+
sInf f :=
157+
{ carrier := ⋂ s ∈ f, s
158+
mul_mem' hx hy := by rw [Set.mem_iInter₂] at *; exact fun s hs ↦ mul_mem (hx s hs) (hy s hs)
159+
one_mem' := Set.mem_iInter₂.mpr fun _ _ ↦ one_mem _
160+
mulSaturated := by
161+
convert Submonoid.MulSaturated.sInf (f := toSubmonoid '' f) (by simp)
162+
ext; simp [Submonoid.mem_sInf] }
163+
164+
@[to_additive]
165+
theorem mem_sInf {f : Set (SaturatedSubmonoid M)} {x : M} : x ∈ sInf f ↔ ∀ s ∈ f, x ∈ s :=
166+
Set.mem_iInter₂
167+
168+
variable (M) in
169+
@[to_additive]
170+
instance : CompleteSemilatticeInf (SaturatedSubmonoid M) where
171+
sInf_le f s hs x hx := mem_sInf.1 hx s hs
172+
le_sInf f s ih x hx := mem_sInf.2 <| by tauto
173+
174+
end SaturatedSubmonoid
175+
176+
namespace Submonoid
177+
178+
/-- The saturation of a submonoid `s` is the intersection of all saturated submonoids that contain
179+
`s`.
180+
181+
If `M` is a commutative monoid, then this is `{x : M | ∃ y : M, x * y ∈ s}`. -/
182+
@[to_additive
183+
/-- The saturation of an additive submonoid `s` is the intersection of all saturated submonoids
184+
that contain `s`.
185+
186+
If `M` is a commutative additive monoid, then this is `{x : M | ∃ y : M, x + y ∈ s}`. -/]
187+
def saturation {M : Type*} [MulOneClass M] (s : Submonoid M) : SaturatedSubmonoid M :=
188+
sInf {t | s ≤ t.toSubmonoid}
189+
190+
variable {M : Type*}
191+
192+
section MulOneClass
193+
variable [MulOneClass M]
194+
195+
variable (M) in
196+
@[to_additive]
197+
theorem gc_saturation : GaloisConnection (saturation (M := M)) (·.toSubmonoid) := fun _ _ ↦
198+
fun ih _ hx ↦ ih <| SaturatedSubmonoid.mem_sInf.mpr fun _ ht ↦ ht hx,
199+
fun ih _ hx ↦ SaturatedSubmonoid.mem_sInf.mp hx _ ih⟩
200+
201+
variable (M) in
202+
/-- `saturation` forms a `GaloisInsertion` with the forgetful functor
203+
`SaturatedSubmonoid.toSubmonoid`. -/
204+
@[to_additive
205+
/-- `saturation` forms a `GaloisInsertion` with the forgetful functor
206+
`SaturatedAddSubmonoid.toAddSubmonoid`. -/]
207+
def giSaturation : GaloisInsertion (saturation (M := M)) (·.toSubmonoid) where
208+
choice s hs := { s with mulSaturated := le_antisymm ((gc_saturation M).le_u_l s) hs ▸ by simp }
209+
gc := gc_saturation M
210+
le_l_u s := (gc_saturation M).le_u_l s.toSubmonoid
211+
choice_eq s h := le_antisymm ((gc_saturation M).le_u_l s) h
212+
213+
variable {a : Submonoid M} {b : SaturatedSubmonoid M}
214+
215+
@[to_additive]
216+
theorem saturation_le_iff_le : a.saturation ≤ b ↔ a ≤ b.toSubmonoid := gc_saturation ..
217+
218+
@[to_additive]
219+
alias ⟨_, saturation_le_of_le⟩ := saturation_le_iff_le
220+
221+
@[to_additive]
222+
theorem le_toSubmonoid_saturation : a ≤ a.saturation.toSubmonoid := (gc_saturation M).le_u_l a
223+
224+
@[to_additive (attr := simp)]
225+
theorem saturation_toSubmonoid : b.saturation = b := (giSaturation M).l_u_eq b
226+
227+
@[to_additive (attr := elab_as_elim)]
228+
theorem saturation_induction {s : Submonoid M}
229+
{p : (x : M) → x ∈ s.saturation → Prop}
230+
(mem : ∀ (x) (hx : x ∈ s), p x (le_toSubmonoid_saturation hx))
231+
(mul : ∀ x y hx hy, p x hx → p y hy → p (x * y) (mul_mem hx hy))
232+
(of_mul : ∀ (x y) (hxy : x * y ∈ s.saturation),
233+
p (x * y) hxy → p x (s.saturation.2 hxy).1 ∧ p y (s.saturation.2 hxy).2)
234+
{x : M} (hx : x ∈ s.saturation) : p x hx := by
235+
let s' : SaturatedSubmonoid M :=
236+
{ carrier := { x | ∃ hx, p x hx }
237+
one_mem' := ⟨_ , mem 1 <| one_mem s⟩
238+
mul_mem' := fun ⟨_, hpx⟩ ⟨_, hpy⟩ ↦ ⟨_, mul _ _ _ _ hpx hpy⟩
239+
mulSaturated := fun x y ⟨_, hpxy⟩ ↦ ⟨⟨_, (of_mul _ _ _ hpxy).1⟩, ⟨_, (of_mul _ _ _ hpxy).2⟩⟩ }
240+
exact SaturatedSubmonoid.mem_sInf.mp hx s' (fun _ h ↦ ⟨_, mem _ h⟩) |>.2
241+
242+
end MulOneClass
243+
244+
section CommMonoid
245+
variable [CommMonoid M]
246+
247+
variable {s : Submonoid M} {x : M}
248+
249+
@[to_additive]
250+
theorem mem_saturation_iff : x ∈ s.saturation ↔ ∃ y, x * y ∈ s := by
251+
refine ⟨fun h ↦ ?_, fun ⟨y, hxy⟩ ↦ (s.saturation.2 <| le_toSubmonoid_saturation hxy).1
252+
induction h using saturation_induction with
253+
| mem _ hx => exact ⟨1, by simpa⟩
254+
| mul _ _ _ _ ih₁ ih₂ =>
255+
exact ih₁.elim fun y₁ h₁ ↦ ih₂.elim fun y₂ h₂ ↦
256+
⟨y₁ * y₂, by rw [mul_mul_mul_comm]; exact mul_mem h₁ h₂⟩
257+
| of_mul x₁ x₂ _ ih =>
258+
exact ih.elim fun y h ↦ ⟨⟨x₂ * y, by rwa [← mul_assoc]⟩,
259+
⟨x₁ * y, by rwa [mul_left_comm, ← mul_assoc]⟩⟩
260+
261+
@[to_additive]
262+
theorem mem_saturation_iff' : x ∈ s.saturation ↔ ∃ y, y * x ∈ s := by
263+
simp_rw [mem_saturation_iff, mul_comm x]
264+
265+
theorem mem_saturation_iff_exists_dvd : x ∈ s.saturation ↔ ∃ m ∈ s, x ∣ m := by
266+
simp_rw [dvd_def, existsAndEq, and_true, mem_saturation_iff]
267+
268+
end CommMonoid
269+
270+
end Submonoid
271+
272+
namespace SaturatedSubmonoid
273+
274+
@[to_additive]
275+
instance (M : Type*) [MulOneClass M] :
276+
CompleteLattice (SaturatedSubmonoid M) :=
277+
{ inferInstanceAs (PartialOrder (SaturatedSubmonoid M)),
278+
inferInstanceAs (Top (SaturatedSubmonoid M)),
279+
inferInstanceAs (Min (SaturatedSubmonoid M)),
280+
inferInstanceAs (CompleteSemilatticeInf (SaturatedSubmonoid M)),
281+
(Submonoid.giSaturation M).liftCompleteLattice with }
282+
283+
variable {M : Type*}
284+
285+
section MulOneClass
286+
variable [MulOneClass M]
287+
288+
@[to_additive]
289+
theorem bot_def : (⊥ : SaturatedSubmonoid M) = Submonoid.saturation ⊥ := rfl
290+
291+
@[to_additive]
292+
theorem sup_def {s₁ s₂ : SaturatedSubmonoid M} :
293+
s₁ ⊔ s₂ = (s₁.toSubmonoid ⊔ s₂.toSubmonoid).saturation := rfl
294+
295+
@[to_additive]
296+
theorem sSup_def {f : Set (SaturatedSubmonoid M)} :
297+
sSup f = (sSup (toSubmonoid '' f)).saturation := rfl
298+
299+
@[to_additive]
300+
theorem iSup_def {ι : Sort*} {f : ι → SaturatedSubmonoid M} :
301+
iSup f = (⨆ i, (f i).toSubmonoid).saturation :=
302+
(Submonoid.giSaturation M).l_iSup_u f |>.symm
303+
304+
end MulOneClass
305+
306+
section CommMonoid
307+
variable [CommMonoid M]
308+
309+
@[to_additive]
310+
theorem mem_bot_iff {x : M} : x ∈ (⊥ : SaturatedSubmonoid M) ↔ IsUnit x := by
311+
simp_rw [bot_def, Submonoid.mem_saturation_iff, Submonoid.mem_bot, isUnit_iff_exists_inv]
312+
313+
end CommMonoid
314+
315+
end SaturatedSubmonoid
316+
317+
namespace Submonoid
318+
variable {M : Type*} [MulOneClass M]
319+
320+
@[to_additive (attr := simp)]
321+
theorem saturation_bot : (⊥ : Submonoid M).saturation = ⊥ := (gc_saturation M).l_bot
322+
323+
@[to_additive (attr := simp)]
324+
theorem saturation_top : (⊤ : Submonoid M).saturation = ⊤ := (giSaturation M).l_top
325+
326+
@[to_additive (attr := simp)]
327+
theorem saturation_sup {s₁ s₂ : Submonoid M} :
328+
(s₁ ⊔ s₂).saturation = s₁.saturation ⊔ s₂.saturation := (gc_saturation M).l_sup
329+
330+
-- note that it does not preserve inf:
331+
-- if s₁ = {6 ^ n | n : ℕ} and s₂ = {15 ^ n | n : ℕ} then
332+
-- (s₁ ⊓ s₂).saturation = {1} and
333+
-- s₁.saturation ⊓ s₂.saturation = {3 ^ n | n : ℕ}
334+
335+
@[to_additive (attr := simp)]
336+
theorem saturation_sSup {f : Set (Submonoid M)} :
337+
(sSup f).saturation = ⨆ s ∈ f, s.saturation := (gc_saturation M).l_sSup
338+
339+
@[to_additive (attr := simp)]
340+
theorem saturation_iSup {ι : Sort*} {f : ι → Submonoid M} :
341+
(iSup f).saturation = ⨆ i, (f i).saturation := (gc_saturation M).l_iSup
342+
343+
end Submonoid

0 commit comments

Comments
 (0)