Skip to content

Commit 58497e3

Browse files
committed
feat(Geometry/Euclidean): volume of a simplex
1 parent 299c071 commit 58497e3

5 files changed

Lines changed: 635 additions & 1 deletion

File tree

Mathlib.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4410,7 +4410,10 @@ public import Mathlib.Geometry.Euclidean.Sphere.Ptolemy
44104410
public import Mathlib.Geometry.Euclidean.Sphere.SecondInter
44114411
public import Mathlib.Geometry.Euclidean.Sphere.Tangent
44124412
public import Mathlib.Geometry.Euclidean.Triangle
4413+
public import Mathlib.Geometry.Euclidean.Volume.Basic
4414+
public import Mathlib.Geometry.Euclidean.Volume.Def
44134415
public import Mathlib.Geometry.Euclidean.Volume.Measure
4416+
public import Mathlib.Geometry.Euclidean.Volume.MeasureSimplex
44144417
public import Mathlib.Geometry.Group.Growth.LinearLowerBound
44154418
public import Mathlib.Geometry.Group.Growth.QuotientInter
44164419
public import Mathlib.Geometry.Manifold.Algebra.LeftInvariantDerivation
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
/-
2+
Copyright (c) 2026 Weiyi Wang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Weiyi Wang
5+
-/
6+
module
7+
8+
public import Mathlib.Geometry.Euclidean.Volume.Def
9+
public import Mathlib.Analysis.InnerProductSpace.GramMatrix
10+
public import Mathlib.Analysis.InnerProductSpace.PiL2
11+
import Mathlib.Geometry.Euclidean.Volume.MeasureSimplex
12+
import Mathlib.MeasureTheory.Measure.Lebesgue.EqHaar
13+
14+
/-!
15+
# Volume of a simplex
16+
17+
This file provides lemma related to the volume of a simplex.
18+
-/
19+
20+
public section
21+
22+
open MeasureTheory Measure
23+
24+
namespace Affine.Simplex
25+
26+
variable {V P : Type*}
27+
variable [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P] [NormedAddTorsor V P]
28+
variable {V₂ P₂ : Type*}
29+
variable [NormedAddCommGroup V₂] [InnerProductSpace ℝ V₂] [MetricSpace P₂] [NormedAddTorsor V₂ P₂]
30+
31+
@[simp]
32+
theorem volume_eq_one (s : Simplex ℝ P 0) : s.volume = 1 := rfl
33+
34+
@[simp]
35+
theorem volume_eq_dist (s : Simplex ℝ P 1) : s.volume = dist (s.points 0) (s.points 1) := by
36+
simp [volume]
37+
38+
theorem volume_eq {n : ℕ} [NeZero n] (s : Simplex ℝ P n) (i : Fin (n + 1)) :
39+
s.volume = (↑n)⁻¹ * s.height i * (s.faceOpposite i).volume := by
40+
obtain ⟨m, rfl⟩ := Nat.exists_add_one_eq.mpr (NeZero.pos n)
41+
borelize P
42+
simp [volume_eq_euclideanHausdorffMeasure_real_closedInterior,
43+
s.euclideanHausdorffMeasure_real_closedInterior i]
44+
45+
@[simp]
46+
theorem volume_reindex {m n : ℕ} (s : Simplex ℝ P n) (e : Fin (n + 1) ≃ Fin (m + 1)) :
47+
(s.reindex e).volume = s.volume := by
48+
borelize P
49+
have hnm : n = m := by simpa using Fin.equiv_iff_eq.mp ⟨e⟩
50+
simp_rw [volume_eq_euclideanHausdorffMeasure_real_closedInterior, hnm, closedInterior_reindex]
51+
52+
@[simp]
53+
theorem volume_map {n : ℕ} (s : Simplex ℝ P n) (f : P →ᵃⁱ[ℝ] P₂) :
54+
(s.map f.toAffineMap f.injective).volume = s.volume := by
55+
by_cases hn : n = 0
56+
· obtain rfl := hn
57+
simp
58+
have : NeZero n := ⟨hn⟩
59+
conv_lhs => rw [volume_eq _ 0]
60+
conv_rhs => rw [volume_eq _ 0]
61+
rw [height_map, faceOpposite_map, volume_map]
62+
63+
@[simp]
64+
theorem volume_map_homothety {n : ℕ} (s : Simplex ℝ P n) (c : P) {r : ℝ} (hr : r ≠ 0) :
65+
(s.map (AffineMap.homothety c r) (AffineMap.homothety_injective c hr)).volume =
66+
|r| ^ n * s.volume := by
67+
borelize P
68+
simp [volume_eq_euclideanHausdorffMeasure_real_closedInterior, measureReal_def,
69+
closedInterior_map, euclideanHausdorffMeasure_homothety_image n c hr]
70+
71+
theorem volume_map_linearMap_eq_det_mul [FiniteDimensional ℝ V]
72+
{n : ℕ} (hn : Module.finrank ℝ V = n) (s : Simplex ℝ V n) (f : V →ₗ[ℝ] V)
73+
(hf : Function.Injective f) :
74+
(s.map f.toAffineMap hf).volume = |f.det| * s.volume := by
75+
borelize V
76+
simp [volume_eq_volume_real_closedInterior hn, closedInterior_map, measureReal_def]
77+
78+
theorem volume_map_eq_det_mul {P₂ : Type*}
79+
[MetricSpace P₂] [NormedAddTorsor V P₂] [FiniteDimensional ℝ V]
80+
{n : ℕ} (hn : Module.finrank ℝ V = n) (s : Simplex ℝ P n) (f : P →ᵃ[ℝ] P₂)
81+
(hf : Function.Injective f) :
82+
(s.map f hf).volume = |f.linear.det| * s.volume := by
83+
obtain p := Classical.arbitrary P
84+
have hfeq : f = (AffineIsometryEquiv.vaddConst ℝ (f p)).toAffineMap.comp
85+
(f.linear.toAffineMap.comp (AffineIsometryEquiv.vaddConst ℝ p).symm.toAffineMap) := by
86+
ext x
87+
simp
88+
have hf' : Function.Injective ((AffineIsometryEquiv.vaddConst ℝ (f p)).toAffineMap.comp
89+
(f.linear.toAffineMap.comp (AffineIsometryEquiv.vaddConst ℝ p).symm) : P →ᵃ[ℝ] P₂) := by
90+
convert hf
91+
exact hfeq.symm
92+
trans (s.map _ hf').volume
93+
· congr
94+
rw [map_comp _ _ (by
95+
rw [AffineMap.coe_comp]
96+
exact Function.Injective.comp (by simpa using hf) (AffineIsometryEquiv.injective _))
97+
_ (AffineIsometryEquiv.injective _)]
98+
simp_rw [show (AffineIsometryEquiv.vaddConst ℝ (f p)).toAffineEquiv.toAffineMap =
99+
(AffineIsometryEquiv.vaddConst ℝ (f p)).toAffineIsometry.toAffineMap by rfl]
100+
rw [volume_map, map_comp _ _ (AffineIsometryEquiv.injective _) _ (by simpa using hf),
101+
volume_map_linearMap_eq_det_mul hn]
102+
congr
103+
exact s.volume_map (AffineIsometryEquiv.vaddConst ℝ p).symm.toAffineIsometry
104+
105+
@[simp]
106+
theorem volume_restrict {n : ℕ} (s : Simplex ℝ P n) (S : AffineSubspace ℝ P)
107+
(hS : affineSpan ℝ (Set.range s.points) ≤ S) :
108+
haveI := Nonempty.map (AffineSubspace.inclusion hS) inferInstance
109+
(s.restrict S hS).volume = s.volume := by
110+
have := Nonempty.map (AffineSubspace.inclusion hS) inferInstance
111+
by_cases hn : n = 0
112+
· obtain rfl := hn
113+
simp
114+
have : NeZero n := ⟨hn⟩
115+
conv_lhs => rw [volume_eq _ 0]
116+
conv_rhs => rw [volume_eq _ 0]
117+
rw [height_restrict, faceOpposite_restrict, volume_restrict]
118+
119+
@[simp]
120+
theorem volume_pos {n : ℕ} (s : Simplex ℝ P n) : 0 < s.volume := by
121+
by_cases hn : n = 0
122+
· obtain rfl := hn
123+
simp
124+
have : NeZero n := ⟨hn⟩
125+
rw [volume_eq _ 0]
126+
have : 0 < (s.faceOpposite 0).volume := volume_pos _
127+
positivity
128+
129+
open Qq Mathlib.Meta.Positivity in
130+
/-- Extension for the `positivity` tactic: the volume of a simplex is always positive. -/
131+
@[positivity volume _]
132+
meta def evalVolume : PositivityExt where eval {u α} _ _ e := do
133+
match u, α, e with
134+
| 0, ~q(ℝ), ~q(@volume $V $P $i1 $i2 $i3 $i4 $n $s) =>
135+
assertInstancesCommute
136+
return .positive q(volume_pos $s)
137+
| _, _, _ => throwError "not Simplex.volume"
138+
139+
----
140+
141+
-- Move this
142+
theorem EuclideanSpace.linearIndependent_single_one
143+
{ι : Type*} {𝕜 : Type*} [RCLike 𝕜] [DecidableEq ι] :
144+
LinearIndependent 𝕜 (fun (i : ι) ↦ EuclideanSpace.single i (1 : 𝕜)) := by
145+
suffices LinearIndependent 𝕜 ((WithLp.linearEquiv 2 𝕜 _).symm.toLinearMap ∘
146+
fun (i : ι) ↦ (Pi.single i (1 : 𝕜))) by
147+
simpa
148+
rw [LinearMap.linearIndependent_iff_of_injOn _ (by simp)]
149+
exact Pi.linearIndependent_single_one ι 𝕜
150+
151+
variable {ι : Type*} [Fintype ι] [DecidableEq ι]
152+
153+
/-- A simplex in the `EuclideanSpace` where one vertex is at the origin, and other vertices are
154+
at `EuclideanSpace.single j 1` for some `j`. -/
155+
noncomputable def cornerSimplex (n : ℕ) (f : Fin (n + 1) ↪ Option ι) (h : none ∈ Set.range f) :
156+
Simplex ℝ (EuclideanSpace ℝ ι) n where
157+
points i := match f i with
158+
| none => 0
159+
| some j => EuclideanSpace.single j 1
160+
independent := by
161+
obtain ⟨k, hk⟩ := Set.mem_range.mp h
162+
rw [affineIndependent_iff_linearIndependent_vsub _ _ k]
163+
simp only [hk, vsub_eq_sub, sub_zero]
164+
suffices LinearIndependent ℝ (fun (i : ι) ↦ EuclideanSpace.single i (1 : ℝ)) by
165+
let f : {i // i ≠ k} → ι := fun i ↦ (f i.val).get (by
166+
obtain hi := i.prop
167+
contrapose! hi
168+
apply f.injective
169+
simpa [hk] using hi
170+
)
171+
have hf : Function.Injective f := by
172+
intro i j h
173+
ext1
174+
simpa [f, Option.get_inj] using h
175+
convert this.comp f hf with i
176+
simp_rw [f]
177+
grind
178+
apply EuclideanSpace.linearIndependent_single_one
179+
180+
theorem faceOpposite_cornerSimplex {n : ℕ} {f : Fin (n + 2) ↪ Option ι} (h : none ∈ Set.range f)
181+
{i : Fin (n + 2)} (hi : f i ≠ none) :
182+
(cornerSimplex (n + 1) f h).faceOpposite i =
183+
cornerSimplex n (i.succAboveEmb.trans f) (by
184+
rw [Set.mem_range] at ⊢ h
185+
obtain ⟨j, hj⟩ := h
186+
have : i ≠ j := by simpa [← f.injective.ne_iff, hj] using hi
187+
obtain ⟨k, hk⟩ := Fin.exists_succAbove_eq this.symm
188+
use k
189+
simp [hk, hj]) := by
190+
ext1 i
191+
rw [faceOpposite_point_eq_point_succAbove]
192+
simp [cornerSimplex]
193+
194+
set_option backward.isDefEq.respectTransparency false in
195+
theorem altitudeFoot_cornerSimplex {n : ℕ} {f : Fin (n + 2) ↪ Option ι} (h : none ∈ Set.range f)
196+
{i : Fin (n + 2)} (hi : f i ≠ none) :
197+
(cornerSimplex (n + 1) f h).altitudeFoot i = 0 := by
198+
obtain ⟨j, hj⟩ := Set.mem_range.mp h
199+
rw [altitudeFoot, orthogonalProjectionSpan, EuclideanGeometry.coe_orthogonalProjection_eq_iff_mem,
200+
faceOpposite_cornerSimplex h hi]
201+
constructor
202+
· apply mem_affineSpan
203+
rw [Set.mem_range]
204+
have : i ≠ j := by simpa [← f.injective.ne_iff, hj] using hi
205+
obtain ⟨k, hk⟩ := Fin.exists_succAbove_eq this.symm
206+
use k
207+
simp [cornerSimplex, hk, hj]
208+
rw [Submodule.mem_orthogonal, direction_affineSpan]
209+
intro u hu
210+
rw [mem_vectorSpan_iff_eq_weightedVSub] at hu
211+
obtain ⟨t, w, hw0, rfl⟩ := hu
212+
rw [Finset.weightedVSub_eq_weightedVSubOfPoint_of_sum_eq_zero _ _ _ hw0 0,
213+
Finset.weightedVSubOfPoint_apply, sum_inner]
214+
refine Finset.sum_eq_zero fun k _ ↦ ?_
215+
cases hk : f (i.succAbove k) with
216+
| none => simp [cornerSimplex, hk]
217+
| some k' =>
218+
cases hi : f i with
219+
| none => simp [cornerSimplex, hi]
220+
| some i' =>
221+
suffices i' ≠ k' by
222+
simp [cornerSimplex, hk, hi, EuclideanSpace.inner_single_right, this]
223+
apply_fun Option.some
224+
simp [← hi, ← hk]
225+
226+
theorem height_cornerSimplex {n : ℕ} {f : Fin (n + 2) ↪ Option ι} (h : none ∈ Set.range f)
227+
{i : Fin (n + 2)} (hi : f i ≠ none) :
228+
(cornerSimplex (n + 1) f h).height i = 1 := by
229+
obtain ⟨j, hj⟩ := Option.ne_none_iff_exists.mp hi
230+
rw [height, altitudeFoot_cornerSimplex h hi]
231+
simp [cornerSimplex, ← hj]
232+
233+
set_option backward.isDefEq.respectTransparency false in
234+
theorem volume_cornerSimplex {n : ℕ} {f : Fin (n + 1) ↪ Option ι} (h : none ∈ Set.range f) :
235+
(cornerSimplex n f h).volume = (n.factorial : ℝ)⁻¹ := by
236+
induction n with
237+
| zero => simp
238+
| succ n ih =>
239+
obtain ⟨i, hi⟩ := Function.Injective.exists_ne f.injective none
240+
rw [volume_eq _ i, height_cornerSimplex h hi, faceOpposite_cornerSimplex h hi, ih,
241+
mul_one, ← mul_inv, ← Nat.cast_mul, Nat.factorial_succ]
242+
243+
theorem volume_eq_det_of_euclideanSpace {n : ℕ}
244+
(s : Simplex ℝ (EuclideanSpace ℝ ι) n) (f : Option ι ≃ Fin (n + 1)) :
245+
s.volume = (n.factorial : ℝ)⁻¹ *
246+
|(Matrix.of fun j i ↦ (s.points (f (some i)) - s.points (f none)) j).det| := by
247+
have hn : Module.finrank ℝ (EuclideanSpace ℝ ι) = n := by
248+
simpa using Fintype.card_eq.mpr ⟨f⟩
249+
let t : Simplex ℝ (EuclideanSpace ℝ ι) n := cornerSimplex n f.symm (by simp)
250+
let ml : EuclideanSpace ℝ ι →ₗ[ℝ] EuclideanSpace ℝ ι:=
251+
(Matrix.of fun (j i : ι) ↦ (s.points (f (some i)) - s.points (f none)).ofLp j).toEuclideanLin
252+
let m : EuclideanSpace ℝ ι →ᵃ[ℝ] EuclideanSpace ℝ ι :=
253+
(AffineIsometryEquiv.vaddConst ℝ (s.points (f none))).toAffineMap.comp ml.toAffineMap
254+
have hmmap (i : Fin (n + 1)) : s.points i = m (t.points i) := by
255+
cases h : f.symm i with
256+
| none =>
257+
obtain h' : i = f none := by simp [← h]
258+
simp [t, cornerSimplex, m, h']
259+
| some j =>
260+
obtain h' : i = f (some j) := by simp [← h]
261+
ext
262+
simp [t, cornerSimplex, m, ml, Matrix.col_eq_transpose, Matrix.transpose, h']
263+
have hm : Function.Bijective m := by
264+
obtain hs := s.independent
265+
obtain ht := t.independent
266+
rw [affineIndependent_iff_linearIndependent_vsub ℝ _ 0] at hs ht
267+
have hmmap' :
268+
(fun (i : { x // x ≠ 0 }) ↦ s.points i.val -ᵥ s.points 0) =
269+
m.linear ∘ (fun (i : { x // x ≠ 0 }) ↦ t.points i.val -ᵥ t.points 0) := by
270+
ext1 i
271+
simp_rw [Function.comp_apply, AffineMap.linearMap_vsub, hmmap]
272+
rw [hmmap'] at hs
273+
rw [← AffineMap.linear_bijective_iff]
274+
refine LinearMap.bijective_of_linearIndependent_of_span_eq_top ?_ hs ?_
275+
all_goals
276+
apply Submodule.eq_top_of_finrank_eq
277+
rw [hn]
278+
rw [finrank_span_eq_card (by assumption)]
279+
simp
280+
have hs : s = t.map m hm.injective := by
281+
ext1 i
282+
simp [ hmmap]
283+
conv_lhs => rw [hs]
284+
rw [volume_map_eq_det_mul hn]
285+
unfold t
286+
rw [volume_cornerSimplex, mul_comm]
287+
simp [m, ml]
288+
289+
theorem volume_eq_det {n : ℕ} {P : Type*} [MetricSpace P] [NormedAddTorsor (EuclideanSpace ℝ ι) P]
290+
(s : Simplex ℝ P n) (f : Option ι ≃ Fin (n + 1)) :
291+
s.volume = (n.factorial : ℝ)⁻¹ *
292+
|(Matrix.of fun j i ↦ (s.points (f (some i)) -ᵥ s.points (f none)) j).det| := by
293+
rw [← s.volume_map (AffineIsometryEquiv.vaddConst ℝ (s.points (f none))).symm.toAffineIsometry]
294+
rw [volume_eq_det_of_euclideanSpace _ f]
295+
simp
296+
297+
theorem volume_eq_det_of_orthonormalBasis {n : ℕ} (s : Simplex ℝ P n) (f : Option ι ≃ Fin (n + 1))
298+
(b : OrthonormalBasis ι ℝ V) :
299+
s.volume = (n.factorial : ℝ)⁻¹ *
300+
|(Matrix.of fun j i ↦ b.repr (s.points (f (some i)) -ᵥ s.points (f none)) j).det| := by
301+
let g : P ≃ᵃⁱ[ℝ] EuclideanSpace ℝ ι :=
302+
(AffineIsometryEquiv.vaddConst ℝ (s.points (f none))).symm.trans
303+
b.repr.toAffineIsometryEquiv
304+
rw [← s.volume_map g.toAffineIsometry]
305+
rw [volume_eq_det_of_euclideanSpace _ f]
306+
simp [g]
307+
308+
theorem volume_eq_gram {n : ℕ} (s : Simplex ℝ P n) (f : Option ι ≃ Fin (n + 1)) :
309+
s.volume = (n.factorial : ℝ)⁻¹ *
310+
√(Matrix.gram ℝ fun i ↦ s.points (f (some i)) -ᵥ s.points (f none)).det := by
311+
have hc : Fintype.card (Fin (n + 1)) = n + 1 := by simp
312+
have hrank : Fintype.card ι = Module.finrank ℝ (affineSpan ℝ (Set.range s.points)).direction := by
313+
rw [direction_affineSpan]
314+
rw [(affineIndependent_iff_finrank_vectorSpan_eq ℝ _ hc).mp s.independent]
315+
simpa using (Fintype.card_eq.mpr ⟨f⟩)
316+
rw [← s.volume_restrict _ le_rfl]
317+
let b : OrthonormalBasis ι ℝ (affineSpan ℝ (Set.range s.points)).direction :=
318+
(stdOrthonormalBasis ℝ _).reindex (Fintype.equivFinOfCardEq hrank).symm
319+
rw [volume_eq_det_of_orthonormalBasis _ f b]
320+
congr
321+
symm
322+
trans √(Matrix.gram ℝ fun i ↦ (⟨s.points (f (some i)) -ᵥ s.points (f none),
323+
AffineSubspace.vsub_mem_direction (mem_affineSpan _ (by simp)) (mem_affineSpan _ (by simp))⟩ :
324+
(affineSpan ℝ (Set.range s.points)).direction)).det
325+
· simp [Matrix.gram] -- extract?
326+
convert (Real.sqrt_sq_eq_abs _)
327+
rw [sq]
328+
nth_rw 2 [← Matrix.det_transpose]
329+
rw [Matrix.gram_eq_conjTranspose_mul b]
330+
rw [Matrix.conjTranspose_eq_transpose_of_trivial]
331+
rw [Matrix.det_mul]
332+
rfl
333+
334+
end Affine.Simplex
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/-
2+
Copyright (c) 2026 Weiyi Wang. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Weiyi Wang
5+
-/
6+
module
7+
8+
public import Mathlib.Geometry.Euclidean.Altitude
9+
10+
/-!
11+
# Volume of a simplex
12+
13+
This file defines the volume of a simplex as `Affine.Simplex.volume`. It is kept thin and
14+
all lemmas are put to `Mathlib.Geometry.Euclidean.Volume.Simplex.Measure` (for connection to volume
15+
measure) and `Mathlib.Geometry.Euclidean.Volume.Simplex.Basic` (for lemmas outside of measure
16+
theory)
17+
-/
18+
19+
@[expose] public section
20+
21+
variable {V P : Type*}
22+
variable [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P] [NormedAddTorsor V P]
23+
24+
/-- The volume of a `n`-dimensional simplex, internally defined using base-and-height formula
25+
from the 0-th vertex.
26+
27+
See also:
28+
* `Affine.Simplex.volume_eq_euclideanHausdorffMeasure_real_closedInterior` for connection between
29+
the defintion and the volume measure.
30+
* `Affine.Simplex.volume_eq` for base-and-height formula from any vertex. -/
31+
noncomputable
32+
def Affine.Simplex.volume {n : ℕ} (s : Simplex ℝ P n) : ℝ := match n with
33+
| 0 => 1
34+
| n + 1 => (↑(n + 1))⁻¹ * s.height 0 * (s.faceOpposite 0).volume

0 commit comments

Comments
 (0)