Skip to content

Commit bb1f406

Browse files
committed
feat(Geometry/Convex): modules are convex spaces (#39531)
Show that every semimodule over an ordered semiring is a convex space. It is sadly impossible to make this a global instance since it creates diamonds with structural instances such as `ConvexSpace R X → ConvexSpace R Y → ConvexSpace R (X × Y)` because `(∑ i, f i).fst = ∑ i, (f i).fst` isn't defeq, ultimately because `Finset.sum` isn't a field of `AddCommMonoid`.
1 parent 1563983 commit bb1f406

7 files changed

Lines changed: 192 additions & 70 deletions

File tree

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4516,6 +4516,7 @@ public import Mathlib.Geometry.Convex.Cone.Simplicial
45164516
public import Mathlib.Geometry.Convex.Cone.TensorProduct
45174517
public import Mathlib.Geometry.Convex.ConvexSpace.AffineSpace
45184518
public import Mathlib.Geometry.Convex.ConvexSpace.Defs
4519+
public import Mathlib.Geometry.Convex.ConvexSpace.Module
45194520
public import Mathlib.Geometry.Convex.ConvexSpace.Prod
45204521
public import Mathlib.Geometry.Diffeology.Basic
45214522
public import Mathlib.Geometry.Euclidean.Altitude

Mathlib/Analysis/Convex/MetricSpace.lean

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public import Mathlib.Analysis.Convex.Combination
99
public import Mathlib.Analysis.Normed.Group.AddTorsor
1010
public import Mathlib.Analysis.Normed.Module.Basic
1111
public import Mathlib.Geometry.Convex.ConvexSpace.AffineSpace
12+
public import Mathlib.Geometry.Convex.ConvexSpace.Module
1213

1314
/-!
1415
@@ -40,11 +41,9 @@ public section
4041

4142
namespace Convexity
4243

43-
attribute [local instance] AddTorsor.toConvexSpace
44-
4544
open ConvexSpace
4645

47-
variable {I X : Type*} [ConvexSpace ℝ X] [MetricSpace X]
46+
variable {I X : Type*}
4847

4948
variable (X) in
5049
/-- A convex metric space is a real convex space with a compatible metric structure.
@@ -56,19 +55,19 @@ In particular, convex subsets of normed affine spaces are convex metric spaces.
5655
Note that there is a separate notion of
5756
[convex metric spaces](https://en.wikipedia.org/wiki/Convex_metric_space) in the literature
5857
that has little to do with this definition. -/
59-
class IsConvexDist : Prop where
58+
class IsConvexDist [inst₁ : ConvexSpace ℝ X] [inst₂ : MetricSpace X] : Prop where
6059
/-- Use `dist_iConvexComb_le` instead. -/
61-
dist_iConvexComb_fst_snd_le (f : StdSimplex ℝ (X × X)) :
60+
dist_iConvexComb_fst_snd_le [inst₁] [inst₂] (f : StdSimplex ℝ (X × X)) :
6261
dist (f.iConvexComb Prod.fst) (f.iConvexComb Prod.snd) ≤ f.iConvexComb fun x ↦ dist x.1 x.2
6362

6463
@[deprecated (since := "2026-05-15")] alias IsConvexMetricSpace := IsConvexDist
6564

66-
variable [IsConvexDist X]
65+
variable [ConvexSpace ℝ X] [MetricSpace X] [IsConvexDist X]
6766

6867
/-- `dist(∑ tᵢ xᵢ, ∑ tᵢ yᵢ) ≤ ∑ tᵢ dist(xᵢ, yᵢ)` -/
6968
lemma dist_iConvexComb_le {ι : Type*} (f : StdSimplex ℝ ι) (x y : ι → X) :
7069
dist (f.iConvexComb x) (f.iConvexComb y) ≤ f.iConvexComb fun i ↦ dist (x i) (y i) := by
71-
simpa [iConvexComb_map, Function.comp_def]
70+
simpa [iConvexComb_map, Finsupp.sum_mapDomain_index, add_mul]
7271
using IsConvexDist.dist_iConvexComb_fst_snd_le (f.map fun i ↦ (x i, y i))
7372

7473
@[deprecated (since := "2026-05-15")] alias dist_convexCombination_right_le := dist_iConvexComb_le
@@ -257,13 +256,13 @@ lemma continuous_convexCombPair' [BoundedSpace X]
257256
@[deprecated (since := "2026-05-15")]
258257
alias continuous_convexComboPair' := continuous_convexCombPair'
259258

259+
variable {R E : Type*} [LinearOrder R] [Field R] [IsStrictOrderedRing R] [AddCommGroup E]
260+
[Module R E] [ConvexSpace R E] [IsModuleConvexSpace R E] {S : Set E}
261+
260262
/-- A convex subset of a vector space is a convex space. -/
261263
-- TODO: this should generalize to arbitrary convex space once `Convex` is redefined.
262264
@[expose, implicit_reducible]
263-
noncomputable def ConvexSpace.ofConvex
264-
{R E : Type*} [LinearOrder R] [Field R] [IsStrictOrderedRing R]
265-
[AddCommGroup E] [Module R E] {S : Set E} (H : Convex R S) :
266-
ConvexSpace R S where
265+
noncomputable def ConvexSpace.ofConvex (H : Convex R S) : ConvexSpace R S where
267266
sConvexComb f :=
268267
⟨sConvexComb (f.map (↑)), by
269268
simpa [sConvexComb_eq_sum, StdSimplex.map, Finsupp.sum_mapDomain_index, add_smul] using
@@ -273,52 +272,49 @@ noncomputable def ConvexSpace.ofConvex
273272
StdSimplex.join, Finsupp.sum_sum_index, Finsupp.sum_smul_index, mul_smul, Finsupp.smul_sum]
274273
sConvexComb_single x := by simp [sConvexComb_eq_sum, ← StdSimplex.mk_single, StdSimplex.map]
275274

276-
lemma isAffineMap_coe {R E : Type*} [LinearOrder R] [Field R] [IsStrictOrderedRing R]
277-
[AddCommGroup E] [Module R E] (S : Set E) (H : Convex R S) :
275+
lemma isAffineMap_coe (S : Set E) (H : Convex R S) :
278276
letI : ConvexSpace R S := .ofConvex H
279277
IsAffineMap R ((↑) : S → E) :=
280278
letI : ConvexSpace R S := .ofConvex H
281279
fun _ ↦ rfl⟩
282280

283281
@[simp]
284-
lemma ConvexSpace.ofConvex.coe_sConvexComb
285-
{R E : Type*} [LinearOrder R] [Field R] [IsStrictOrderedRing R]
286-
[AddCommGroup E] [Module R E] (S : Set E) (H : Convex R S) (f : StdSimplex R S) :
282+
lemma ConvexSpace.ofConvex.coe_sConvexComb (S : Set E) (H : Convex R S) (f : StdSimplex R S) :
287283
letI : ConvexSpace R S := .ofConvex H
288284
(↑f.sConvexComb : E) = (f.map (↑)).sConvexComb :=
289285
rfl
290286

291287
@[simp]
292-
lemma ConvexSpace.ofConvex.coe_iConvexComb
293-
{R I E : Type*} [LinearOrder R] [Field R] [IsStrictOrderedRing R]
294-
[AddCommGroup E] [Module R E] (S : Set E) (H : Convex R S) (f : StdSimplex R I) (g : I → S) :
288+
lemma ConvexSpace.ofConvex.coe_iConvexComb (S : Set E) (H : Convex R S) (f : StdSimplex R I)
289+
(g : I → S) :
295290
letI : ConvexSpace R S := .ofConvex H
296291
(↑(f.iConvexComb g) : E) = f.iConvexComb fun x ↦ ↑(g x) :=
297292
letI : ConvexSpace R S := .ofConvex H
298293
(isAffineMap_coe S H).map_iConvexComb f g
299294

295+
attribute [local instance] AddTorsor.toConvexSpace in
300296
instance (priority := low) {V P : Type*}
301297
[NormedAddCommGroup V] [NormedSpace ℝ V] [MetricSpace P] [NormedAddTorsor V P] :
302298
IsConvexDist P where
303299
dist_iConvexComb_fst_snd_le f := by
304300
let p : P := Nonempty.some inferInstance
305-
simp only [AddTorsor.iConvexComb_eq_affineCombination, ge_iff_le]
301+
simp only [AddTorsor.iConvexComb_eq_affineCombination]
306302
rw [Finset.affineCombination_eq_weightedVSubOfPoint_vadd_of_sum_eq_one _ _ _ f.total p,
307-
Finset.affineCombination_eq_weightedVSubOfPoint_vadd_of_sum_eq_one _ _ _ f.total p,
308-
Finset.affineCombination_eq_weightedVSubOfPoint_vadd_of_sum_eq_one _ _ _ f.total 0]
303+
Finset.affineCombination_eq_weightedVSubOfPoint_vadd_of_sum_eq_one _ _ _ f.total p]
309304
suffices ‖f.weights.sum fun a b ↦ b • (a.1 -ᵥ a.2)‖ ≤
310305
f.weights.sum fun a b ↦ b * ‖a.1 -ᵥ a.2by
311306
simpa [dist_eq_norm_vsub, Finsupp.sum, ← Finset.sum_sub_distrib, ← smul_sub]
312307
grw [Finsupp.sum, Finsupp.sum, norm_sum_le]
313308
simp [norm_smul, abs_eq_self.mpr (f.nonneg _)]
314309

315310
instance IsConvexDist.of_convex {E : Type*} [NormedAddCommGroup E]
316-
[NormedSpace ℝ E] {S : Set E} (H : Convex ℝ S) :
311+
[NormedSpace ℝ E] [ConvexSpace ℝ E] [IsModuleConvexSpace ℝ E] [IsConvexDist E] {S : Set E}
312+
(H : Convex ℝ S) :
317313
letI : ConvexSpace ℝ S := .ofConvex H
318314
IsConvexDist S := by
319315
letI : ConvexSpace ℝ S := .ofConvex H
320316
refine ⟨fun f ↦ ?_⟩
321317
convert dist_iConvexComb_fst_snd_le (X := E) (f.map fun x ↦ (x.1, x.2)) <;>
322-
simp [Subtype.dist_eq, iConvexComb_map, Function.comp_def]
318+
simp [Subtype.dist_eq, Finsupp.sum_mapDomain_index, add_mul, add_smul]
323319

324320
end Convexity

Mathlib/Data/Finsupp/Defs.lean

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,17 @@ section OnFinset
227227
variable [Zero M]
228228

229229
/-- The (not exposed) support of `Finsupp.onFinset`. -/
230-
@[no_expose] def onFinset_support (s : Finset α) (f : α → M) : Finset α :=
230+
@[no_expose] def onFinsetSupport (s : Finset α) (f : α → M) : Finset α :=
231231
haveI := Classical.decEq M
232232
{a ∈ s | f a ≠ 0}
233233

234234
/-- `Finsupp.onFinset s f hf` is the finsupp function representing `f` restricted to the finset `s`.
235235
The function must be `0` outside of `s`. Use this when the set needs to be filtered anyways,
236236
otherwise a better set representation is often available. -/
237237
def onFinset (s : Finset α) (f : α → M) (hf : ∀ a, f a ≠ 0 → a ∈ s) : α →₀ M where
238-
support := onFinset_support s f
238+
support := onFinsetSupport s f
239239
toFun := f
240-
mem_support_toFun := by simpa [onFinset_support]
240+
mem_support_toFun := by simpa [onFinsetSupport]
241241

242242
@[simp, norm_cast] lemma coe_onFinset (s : Finset α) (f : α → M) (hf) : onFinset s f hf = f := rfl
243243

@@ -248,7 +248,9 @@ theorem onFinset_apply {s : Finset α} {f : α → M} {hf a} : (onFinset s f hf
248248
theorem support_onFinset [DecidableEq M] {s : Finset α} {f : α → M}
249249
(hf : ∀ a : α, f a ≠ 0 → a ∈ s) :
250250
(Finsupp.onFinset s f hf).support = {a ∈ s | f a ≠ 0} := by
251-
dsimp [onFinset]; rw [onFinset_support]; congr
251+
dsimp [onFinset]; rw [onFinsetSupport]; congr
252+
253+
@[simp] lemma onFinset_support (f : α →₀ M) : onFinset f.support f (by simp) = f := by ext; simp
252254

253255
@[simp]
254256
theorem support_onFinset_subset {s : Finset α} {f : α → M} {hf} :

Mathlib/Geometry/Convex/ConvexSpace/AffineSpace.lean

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ This file shows that every affine space is a convex space.
1616
1717
## Main results
1818
19-
* `AddTorsor.instConvexSpace`: An affine space over a module is a convex space.
20-
* `AddTorsor.convexCombination_eq_affineCombination`: The convex combination equals the affine
19+
* `AddTorsor.toConvexSpace`: An affine space over a module is a convex space.
20+
* `AddTorsor.sConvexComb_eq_affineCombination`: The convex combination equals the affine
2121
combination.
2222
* `AddTorsor.convexCombPair_eq_lineMap`: Binary convex combinations are given by `lineMap`.
2323
-/
@@ -158,33 +158,3 @@ theorem convexCombPair_eq_lineMap (s t : R) (hs : 0 ≤ s) (ht : 0 ≤ t)
158158
simp [vsub_self]
159159

160160
end AddTorsor
161-
162-
open Finsupp
163-
164-
namespace Convexity
165-
166-
attribute [local instance] AddTorsor.toConvexSpace
167-
168-
theorem sConvexComb_eq_sum (f : StdSimplex R V) :
169-
f.sConvexComb = f.weights.sum fun i r ↦ r • i := by
170-
simp [AddTorsor.sConvexComb_eq_affineCombination,
171-
Finset.affineCombination_eq_linear_combination _ _ _ f.total, Finsupp.sum]
172-
173-
@[deprecated (since := "2026-04-03")]
174-
alias _root_.convexCombination_eq_sum := sConvexComb_eq_sum
175-
176-
theorem iConvexComb_eq_sum (f : StdSimplex R I) (g : I → V) :
177-
f.iConvexComb g = f.weights.sum fun i r ↦ r • g i := by
178-
simp [iConvexComb, sConvexComb_eq_sum, add_smul, sum_mapDomain_index]
179-
180-
theorem convexCombPair_eq_add
181-
{s t : R} (hs : 0 ≤ s) (ht : 0 ≤ t) (h : s + t = 1) (x y : V) :
182-
convexCombPair s t hs ht h x y = s • x + t • y := by
183-
classical
184-
simp [convexCombPair, sConvexComb_eq_sum, sum_add_index, add_smul]
185-
186-
variable (R I) in
187-
lemma StdSimplex.isAffineMap_weights : IsAffineMap R (weights (R := R) (M := I)) where
188-
map_sConvexComb s := by simp [sConvexComb_eq_sum, StdSimplex.map, sum_mapDomain_index, add_smul]
189-
190-
end Convexity

Mathlib/Geometry/Convex/ConvexSpace/Defs.lean

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,19 +292,30 @@ lemma sConvexComb_map (w : StdSimplex R I) (f : I → M) :
292292
@[simp] lemma iConvexComb_single (i : I) (f : I → M) :
293293
(single (R := R) i).iConvexComb f = f i := by simp [iConvexComb]
294294

295-
@[simp] lemma iConvexComb_id (s : StdSimplex R M) :
296-
s.iConvexComb id = s.sConvexComb := by simp [iConvexComb]
295+
lemma iConvexComb_id (w : StdSimplex R M) : w.iConvexComb id = w.sConvexComb := by
296+
simp [iConvexComb]
297297

298-
@[simp] lemma iConvexComb_id' (s : StdSimplex R M) :
299-
s.iConvexComb (fun x ↦ x) = s.sConvexComb := iConvexComb_id s
298+
@[simp] lemma iConvexComb_id' (w : StdSimplex R M) :
299+
w.iConvexComb (fun x ↦ x) = w.sConvexComb := iConvexComb_id _
300300

301301
@[simp] lemma iConvexComb_map (s : StdSimplex R I) (f : I → J) (g : J → M) :
302302
(s.map f).iConvexComb g = s.iConvexComb (g ∘ f) := by
303303
simp only [iConvexComb, map_comp]
304304

305-
lemma iConvexComb_congr (s : StdSimplex R I) (f : I ≃ J) (g : I → M) :
305+
@[congr] lemma iConvexComb_congr {w : StdSimplex R I} {f g : I → M}
306+
(hfg : ∀ i, w.weights i ≠ 0 → f i = g i) :
307+
w.iConvexComb f = w.iConvexComb g := by
308+
refine congr(sConvexComb $(?_))
309+
ext i
310+
simp only [weights_map]
311+
-- TODO: This should just be `congr! 2 with i hi`.
312+
congr 1
313+
refine Finsupp.mapDomain_congr fun i hi ↦ ?_
314+
exact hfg i (by simpa using hi)
315+
316+
lemma iConvexComb_reindex (s : StdSimplex R I) (f : I ≃ J) (g : I → M) :
306317
s.iConvexComb g = (s.map f).iConvexComb (g ∘ f.symm) := by
307-
simp [iConvexComb_map, Function.comp_def]
318+
simp [iConvexComb_map]
308319

309320
/-- Flattening nested `iConvexComb`s.
310321
@@ -347,7 +358,7 @@ lemma iConvexComb_comm (f : StdSimplex R I) (g : StdSimplex R J)
347358
(e : I → J → M) :
348359
f.iConvexComb (fun i ↦ g.iConvexComb (e i)) =
349360
g.iConvexComb fun j ↦ f.iConvexComb fun i ↦ e i j := by
350-
rw [iConvexComb_assoc', iConvexComb_assoc', iConvexComb_congr _ (.prodComm ..)]
361+
rw [iConvexComb_assoc', iConvexComb_assoc', iConvexComb_reindex _ (.prodComm ..)]
351362
congr
352363
suffices (f.map fun x ↦ g.map (Prod.mk · x)).sConvexComb =
353364
(g.map (f.map ∘ Prod.mk)).sConvexComb by
@@ -494,7 +505,7 @@ lemma iConvexComb_convexCombPair_comm (f : StdSimplex R I) (e₁ e₂ : I → M)
494505
f.iConvexComb (fun x ↦ convexCombPair s t hs ht h (e₁ x) (e₂ x)) =
495506
convexCombPair s t hs ht h (f.iConvexComb e₁) (f.iConvexComb e₂) := by
496507
simp only [convexCombPair_def]
497-
convert (iConvexComb_comm (.duple 0 1 hs ht h) f ![e₁, e₂]).symm with i j j
508+
convert (iConvexComb_comm (.duple 0 1 hs ht h) f ![e₁, e₂]).symm with i _ j _ j
498509
· fin_cases j <;> simp
499510
· fin_cases j <;> simp
500511

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/-
2+
Copyright (c) 2026 Yaël Dillies. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Yaël Dillies
5+
-/
6+
module
7+
8+
public import Mathlib.Geometry.Convex.ConvexSpace.Prod
9+
public import Mathlib.LinearAlgebra.AffineSpace.Combination
10+
public import Mathlib.LinearAlgebra.AffineSpace.AffineMap
11+
12+
/-!
13+
# Modules are convex spaces
14+
15+
This file shows that every module over ordered coefficients is a convex space.
16+
17+
## Main declarations
18+
19+
* `ConvexSpace.ofModule`: A semimodule space over a semiring is a convex space.
20+
* `convexSpaceSelf`: A semiring is a convex space over itself.
21+
* `IsModuleConvexSpace`: Predicate for a convex space and module structures to be compatible.
22+
-/
23+
24+
public section
25+
26+
namespace Convexity
27+
variable {R M N I : Type*} [Semiring R] [PartialOrder R] [IsStrictOrderedRing R]
28+
[AddCommMonoid M] [Module R M] [AddCommMonoid N] [Module R N]
29+
30+
/-- Any semimodule over an ordered semiring is a convex space.
31+
32+
This is not an instance because it creates a diamond with structural instances such as
33+
`ConvexSpace R X → ConvexSpace R Y → ConvexSpace R (X × Y)` because
34+
`(∑ i, f i).fst = ∑ i, (f i).fst` isn't defeq, ultimately because `Finset.sum` isn't a field of
35+
`AddCommMonoid` but derived from them through recursion. -/
36+
@[expose, implicit_reducible]
37+
def ConvexSpace.ofModule : ConvexSpace R M where
38+
sConvexComb w := w.weights.sum fun m r ↦ r • m
39+
sConvexComb_single := by simp
40+
assoc := by
41+
simp [Finsupp.sum_mapDomain_index, add_smul, Finsupp.sum_sum_index, Finsupp.sum_smul_index,
42+
mul_smul, Finsupp.smul_sum]
43+
44+
instance convexSpaceSelf : ConvexSpace R R := .ofModule
45+
46+
variable (R M) [ConvexSpace R M] in
47+
/-- Typeclass for a convex space structure on a module to be given by weighted sums. -/
48+
class IsModuleConvexSpace : Prop where
49+
sConvexComb_eq_sum (w : StdSimplex R M) : w.sConvexComb = w.weights.sum fun m r ↦ r • m
50+
51+
export IsModuleConvexSpace (sConvexComb_eq_sum)
52+
attribute [simp] sConvexComb_eq_sum
53+
54+
@[deprecated (since := "2026-04-03")]
55+
alias _root_.convexCombination_eq_sum := sConvexComb_eq_sum
56+
57+
attribute [local instance] ConvexSpace.ofModule in
58+
protected lemma IsModuleConvexSpace.ofModule : IsModuleConvexSpace R M where
59+
sConvexComb_eq_sum _ := rfl
60+
61+
instance isModuleConvexSpace_self : IsModuleConvexSpace R R := .ofModule
62+
63+
section IsModuleConvexSpace
64+
variable [ConvexSpace R M] [IsModuleConvexSpace R M]
65+
66+
/-- `iConvexComb` in a module can be expressed as a sum. -/
67+
@[simp]
68+
lemma iConvexComb_eq_sum (w : StdSimplex R I) (f : I → M) :
69+
w.iConvexComb f = w.weights.sum fun i r ↦ r • f i := by
70+
simp [iConvexComb, sConvexComb_eq_sum, Finsupp.sum_mapDomain_index, add_smul]
71+
72+
/-- `convexCombPair` in a module can be expressed as a sum. -/
73+
@[simp]
74+
lemma convexCombPair_eq_sum (a b : R) (ha hb hab) (x y : M) :
75+
convexCombPair a b ha hb hab x y = a • x + b • y := by
76+
classical simp [convexCombPair, sConvexComb_eq_sum, Finsupp.sum_add_index, add_smul]
77+
78+
instance [ConvexSpace R N] [IsModuleConvexSpace R N] : IsModuleConvexSpace R (M × N) where
79+
sConvexComb_eq_sum w := by ext <;> simp [Finsupp.sum, Prod.fst_sum, Prod.snd_sum]
80+
81+
instance {ι : Type*} {M : ι → Type*} [∀ i, AddCommMonoid (M i)] [∀ i, Module R (M i)]
82+
[∀ i, ConvexSpace R (M i)] [∀ i, IsModuleConvexSpace R (M i)] :
83+
IsModuleConvexSpace R (∀ i, M i) where
84+
sConvexComb_eq_sum w := by ext; simp [Finsupp.sum]
85+
86+
instance {ι : Type*} : IsModuleConvexSpace R (ι →₀ M) where
87+
sConvexComb_eq_sum w := by ext; simp [Finsupp.sum]
88+
89+
end IsModuleConvexSpace
90+
91+
variable (R I) in
92+
lemma StdSimplex.isAffineMap_weights : IsAffineMap R (weights (R := R) (M := I)) where
93+
map_sConvexComb s := by simp [sConvexComb_eq_sum, Finsupp.sum_mapDomain_index, add_smul]
94+
95+
end Convexity

0 commit comments

Comments
 (0)