|
| 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 |
0 commit comments