-
Notifications
You must be signed in to change notification settings - Fork 251
/
Orientation.lean
348 lines (295 loc) · 16.8 KB
/
Orientation.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/-
Copyright (c) 2022 Joseph Myers. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Myers, Heather Macbeth
-/
import Mathlib.Analysis.InnerProductSpace.GramSchmidtOrtho
import Mathlib.LinearAlgebra.Orientation
#align_import analysis.inner_product_space.orientation from "leanprover-community/mathlib"@"bd65478311e4dfd41f48bf38c7e3b02fb75d0163"
/-!
# Orientations of real inner product spaces.
This file provides definitions and proves lemmas about orientations of real inner product spaces.
## Main definitions
* `OrthonormalBasis.adjustToOrientation` takes an orthonormal basis and an orientation, and
returns an orthonormal basis with that orientation: either the original orthonormal basis, or one
constructed by negating a single (arbitrary) basis vector.
* `Orientation.finOrthonormalBasis` is an orthonormal basis, indexed by `Fin n`, with the given
orientation.
* `Orientation.volumeForm` is a nonvanishing top-dimensional alternating form on an oriented real
inner product space, uniquely defined by compatibility with the orientation and inner product
structure.
## Main theorems
* `Orientation.volumeForm_apply_le` states that the result of applying the volume form to a set of
`n` vectors, where `n` is the dimension the inner product space, is bounded by the product of the
lengths of the vectors.
* `Orientation.abs_volumeForm_apply_of_pairwise_orthogonal` states that the result of applying the
volume form to a set of `n` orthogonal vectors, where `n` is the dimension the inner product
space, is equal up to sign to the product of the lengths of the vectors.
-/
noncomputable section
variable {E : Type*} [NormedAddCommGroup E] [InnerProductSpace ℝ E]
open FiniteDimensional
open scoped RealInnerProductSpace
namespace OrthonormalBasis
variable {ι : Type*} [Fintype ι] [DecidableEq ι] [ne : Nonempty ι] (e f : OrthonormalBasis ι ℝ E)
(x : Orientation ℝ E ι)
/-- The change-of-basis matrix between two orthonormal bases with the same orientation has
determinant 1. -/
theorem det_to_matrix_orthonormalBasis_of_same_orientation
(h : e.toBasis.orientation = f.toBasis.orientation) : e.toBasis.det f = 1 := by
apply (e.det_to_matrix_orthonormalBasis_real f).resolve_right
have : 0 < e.toBasis.det f := by
rw [e.toBasis.orientation_eq_iff_det_pos] at h
simpa using h
linarith
#align orthonormal_basis.det_to_matrix_orthonormal_basis_of_same_orientation OrthonormalBasis.det_to_matrix_orthonormalBasis_of_same_orientation
/-- The change-of-basis matrix between two orthonormal bases with the opposite orientations has
determinant -1. -/
theorem det_to_matrix_orthonormalBasis_of_opposite_orientation
(h : e.toBasis.orientation ≠ f.toBasis.orientation) : e.toBasis.det f = -1 := by
contrapose! h
simp [e.toBasis.orientation_eq_iff_det_pos,
(e.det_to_matrix_orthonormalBasis_real f).resolve_right h]
#align orthonormal_basis.det_to_matrix_orthonormal_basis_of_opposite_orientation OrthonormalBasis.det_to_matrix_orthonormalBasis_of_opposite_orientation
variable {e f}
/-- Two orthonormal bases with the same orientation determine the same "determinant" top-dimensional
form on `E`, and conversely. -/
theorem same_orientation_iff_det_eq_det :
e.toBasis.det = f.toBasis.det ↔ e.toBasis.orientation = f.toBasis.orientation := by
constructor
· intro h
dsimp [Basis.orientation]
congr
· intro h
rw [e.toBasis.det.eq_smul_basis_det f.toBasis]
simp [e.det_to_matrix_orthonormalBasis_of_same_orientation f h]
#align orthonormal_basis.same_orientation_iff_det_eq_det OrthonormalBasis.same_orientation_iff_det_eq_det
variable (e f)
/-- Two orthonormal bases with opposite orientations determine opposite "determinant"
top-dimensional forms on `E`. -/
theorem det_eq_neg_det_of_opposite_orientation (h : e.toBasis.orientation ≠ f.toBasis.orientation) :
e.toBasis.det = -f.toBasis.det := by
rw [e.toBasis.det.eq_smul_basis_det f.toBasis]
-- Porting note: added `neg_one_smul` with explicit type
simp [e.det_to_matrix_orthonormalBasis_of_opposite_orientation f h,
neg_one_smul ℝ (M := E [⋀^ι]→ₗ[ℝ] ℝ)]
#align orthonormal_basis.det_eq_neg_det_of_opposite_orientation OrthonormalBasis.det_eq_neg_det_of_opposite_orientation
section AdjustToOrientation
/-- `OrthonormalBasis.adjustToOrientation`, applied to an orthonormal basis, preserves the
property of orthonormality. -/
theorem orthonormal_adjustToOrientation : Orthonormal ℝ (e.toBasis.adjustToOrientation x) := by
apply e.orthonormal.orthonormal_of_forall_eq_or_eq_neg
simpa using e.toBasis.adjustToOrientation_apply_eq_or_eq_neg x
#align orthonormal_basis.orthonormal_adjust_to_orientation OrthonormalBasis.orthonormal_adjustToOrientation
/-- Given an orthonormal basis and an orientation, return an orthonormal basis giving that
orientation: either the original basis, or one constructed by negating a single (arbitrary) basis
vector. -/
def adjustToOrientation : OrthonormalBasis ι ℝ E :=
(e.toBasis.adjustToOrientation x).toOrthonormalBasis (e.orthonormal_adjustToOrientation x)
#align orthonormal_basis.adjust_to_orientation OrthonormalBasis.adjustToOrientation
theorem toBasis_adjustToOrientation :
(e.adjustToOrientation x).toBasis = e.toBasis.adjustToOrientation x :=
(e.toBasis.adjustToOrientation x).toBasis_toOrthonormalBasis _
#align orthonormal_basis.to_basis_adjust_to_orientation OrthonormalBasis.toBasis_adjustToOrientation
/-- `adjustToOrientation` gives an orthonormal basis with the required orientation. -/
@[simp]
theorem orientation_adjustToOrientation : (e.adjustToOrientation x).toBasis.orientation = x := by
rw [e.toBasis_adjustToOrientation]
exact e.toBasis.orientation_adjustToOrientation x
#align orthonormal_basis.orientation_adjust_to_orientation OrthonormalBasis.orientation_adjustToOrientation
/-- Every basis vector from `adjustToOrientation` is either that from the original basis or its
negation. -/
theorem adjustToOrientation_apply_eq_or_eq_neg (i : ι) :
e.adjustToOrientation x i = e i ∨ e.adjustToOrientation x i = -e i := by
simpa [← e.toBasis_adjustToOrientation] using
e.toBasis.adjustToOrientation_apply_eq_or_eq_neg x i
#align orthonormal_basis.adjust_to_orientation_apply_eq_or_eq_neg OrthonormalBasis.adjustToOrientation_apply_eq_or_eq_neg
theorem det_adjustToOrientation :
(e.adjustToOrientation x).toBasis.det = e.toBasis.det ∨
(e.adjustToOrientation x).toBasis.det = -e.toBasis.det := by
simpa using e.toBasis.det_adjustToOrientation x
#align orthonormal_basis.det_adjust_to_orientation OrthonormalBasis.det_adjustToOrientation
theorem abs_det_adjustToOrientation (v : ι → E) :
|(e.adjustToOrientation x).toBasis.det v| = |e.toBasis.det v| := by
simp [toBasis_adjustToOrientation]
#align orthonormal_basis.abs_det_adjust_to_orientation OrthonormalBasis.abs_det_adjustToOrientation
end AdjustToOrientation
end OrthonormalBasis
namespace Orientation
variable {n : ℕ}
open OrthonormalBasis
/-- An orthonormal basis, indexed by `Fin n`, with the given orientation. -/
protected def finOrthonormalBasis (hn : 0 < n) (h : finrank ℝ E = n) (x : Orientation ℝ E (Fin n)) :
OrthonormalBasis (Fin n) ℝ E := by
haveI := Fin.pos_iff_nonempty.1 hn
haveI : FiniteDimensional ℝ E := .of_finrank_pos <| h.symm ▸ hn
exact ((@stdOrthonormalBasis _ _ _ _ _ this).reindex <| finCongr h).adjustToOrientation x
#align orientation.fin_orthonormal_basis Orientation.finOrthonormalBasis
/-- `Orientation.finOrthonormalBasis` gives a basis with the required orientation. -/
@[simp]
theorem finOrthonormalBasis_orientation (hn : 0 < n) (h : finrank ℝ E = n)
(x : Orientation ℝ E (Fin n)) : (x.finOrthonormalBasis hn h).toBasis.orientation = x := by
haveI := Fin.pos_iff_nonempty.1 hn
haveI : FiniteDimensional ℝ E := .of_finrank_pos <| h.symm ▸ hn
exact ((@stdOrthonormalBasis _ _ _ _ _ this).reindex <|
finCongr h).orientation_adjustToOrientation x
#align orientation.fin_orthonormal_basis_orientation Orientation.finOrthonormalBasis_orientation
section VolumeForm
variable [_i : Fact (finrank ℝ E = n)] (o : Orientation ℝ E (Fin n))
/-- The volume form on an oriented real inner product space, a nonvanishing top-dimensional
alternating form uniquely defined by compatibility with the orientation and inner product structure.
-/
irreducible_def volumeForm : E [⋀^Fin n]→ₗ[ℝ] ℝ := by
classical
cases' n with n
· let opos : E [⋀^Fin 0]→ₗ[ℝ] ℝ := .constOfIsEmpty ℝ E (Fin 0) (1 : ℝ)
exact o.eq_or_eq_neg_of_isEmpty.by_cases (fun _ => opos) fun _ => -opos
· exact (o.finOrthonormalBasis n.succ_pos _i.out).toBasis.det
#align orientation.volume_form Orientation.volumeForm
@[simp]
theorem volumeForm_zero_pos [_i : Fact (finrank ℝ E = 0)] :
Orientation.volumeForm (positiveOrientation : Orientation ℝ E (Fin 0)) =
AlternatingMap.constLinearEquivOfIsEmpty 1 := by
simp [volumeForm, Or.by_cases, if_pos]
#align orientation.volume_form_zero_pos Orientation.volumeForm_zero_pos
theorem volumeForm_zero_neg [_i : Fact (finrank ℝ E = 0)] :
Orientation.volumeForm (-positiveOrientation : Orientation ℝ E (Fin 0)) =
-AlternatingMap.constLinearEquivOfIsEmpty 1 := by
simp_rw [volumeForm, Or.by_cases, positiveOrientation]
apply if_neg
simp only [neg_rayOfNeZero]
rw [ray_eq_iff, SameRay.sameRay_comm]
intro h
simpa using
congr_arg AlternatingMap.constLinearEquivOfIsEmpty.symm (eq_zero_of_sameRay_self_neg h)
#align orientation.volume_form_zero_neg Orientation.volumeForm_zero_neg
/-- The volume form on an oriented real inner product space can be evaluated as the determinant with
respect to any orthonormal basis of the space compatible with the orientation. -/
theorem volumeForm_robust (b : OrthonormalBasis (Fin n) ℝ E) (hb : b.toBasis.orientation = o) :
o.volumeForm = b.toBasis.det := by
cases n
· classical
have : o = positiveOrientation := hb.symm.trans b.toBasis.orientation_isEmpty
simp_rw [volumeForm, Or.by_cases, dif_pos this, Nat.rec_zero, Basis.det_isEmpty]
· simp_rw [volumeForm]
rw [same_orientation_iff_det_eq_det, hb]
exact o.finOrthonormalBasis_orientation _ _
#align orientation.volume_form_robust Orientation.volumeForm_robust
/-- The volume form on an oriented real inner product space can be evaluated as the determinant with
respect to any orthonormal basis of the space compatible with the orientation. -/
theorem volumeForm_robust_neg (b : OrthonormalBasis (Fin n) ℝ E) (hb : b.toBasis.orientation ≠ o) :
o.volumeForm = -b.toBasis.det := by
cases' n with n
· classical
have : positiveOrientation ≠ o := by rwa [b.toBasis.orientation_isEmpty] at hb
simp_rw [volumeForm, Or.by_cases, dif_neg this.symm, Nat.rec_zero, Basis.det_isEmpty]
let e : OrthonormalBasis (Fin n.succ) ℝ E := o.finOrthonormalBasis n.succ_pos Fact.out
simp_rw [volumeForm]
apply e.det_eq_neg_det_of_opposite_orientation b
convert hb.symm
exact o.finOrthonormalBasis_orientation _ _
#align orientation.volume_form_robust_neg Orientation.volumeForm_robust_neg
@[simp]
theorem volumeForm_neg_orientation : (-o).volumeForm = -o.volumeForm := by
cases' n with n
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl
· simp [volumeForm_zero_neg]
· rw [neg_neg (positiveOrientation (R := ℝ))] -- Porting note: added
simp [volumeForm_zero_neg]
let e : OrthonormalBasis (Fin n.succ) ℝ E := o.finOrthonormalBasis n.succ_pos Fact.out
have h₁ : e.toBasis.orientation = o := o.finOrthonormalBasis_orientation _ _
have h₂ : e.toBasis.orientation ≠ -o := by
symm
rw [e.toBasis.orientation_ne_iff_eq_neg, h₁]
rw [o.volumeForm_robust e h₁, (-o).volumeForm_robust_neg e h₂]
#align orientation.volume_form_neg_orientation Orientation.volumeForm_neg_orientation
theorem volumeForm_robust' (b : OrthonormalBasis (Fin n) ℝ E) (v : Fin n → E) :
|o.volumeForm v| = |b.toBasis.det v| := by
cases n
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl <;> simp
· rw [o.volumeForm_robust (b.adjustToOrientation o) (b.orientation_adjustToOrientation o),
b.abs_det_adjustToOrientation]
#align orientation.volume_form_robust' Orientation.volumeForm_robust'
/-- Let `v` be an indexed family of `n` vectors in an oriented `n`-dimensional real inner
product space `E`. The output of the volume form of `E` when evaluated on `v` is bounded in absolute
value by the product of the norms of the vectors `v i`. -/
theorem abs_volumeForm_apply_le (v : Fin n → E) : |o.volumeForm v| ≤ ∏ i : Fin n, ‖v i‖ := by
cases' n with n
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl <;> simp
haveI : FiniteDimensional ℝ E := .of_fact_finrank_eq_succ n
have : finrank ℝ E = Fintype.card (Fin n.succ) := by simpa using _i.out
let b : OrthonormalBasis (Fin n.succ) ℝ E := gramSchmidtOrthonormalBasis this v
have hb : b.toBasis.det v = ∏ i, ⟪b i, v i⟫ := gramSchmidtOrthonormalBasis_det this v
rw [o.volumeForm_robust' b, hb, Finset.abs_prod]
apply Finset.prod_le_prod
· intro i _
positivity
intro i _
convert abs_real_inner_le_norm (b i) (v i)
simp [b.orthonormal.1 i]
#align orientation.abs_volume_form_apply_le Orientation.abs_volumeForm_apply_le
theorem volumeForm_apply_le (v : Fin n → E) : o.volumeForm v ≤ ∏ i : Fin n, ‖v i‖ :=
(le_abs_self _).trans (o.abs_volumeForm_apply_le v)
#align orientation.volume_form_apply_le Orientation.volumeForm_apply_le
/-- Let `v` be an indexed family of `n` orthogonal vectors in an oriented `n`-dimensional
real inner product space `E`. The output of the volume form of `E` when evaluated on `v` is, up to
sign, the product of the norms of the vectors `v i`. -/
theorem abs_volumeForm_apply_of_pairwise_orthogonal {v : Fin n → E}
(hv : Pairwise fun i j => ⟪v i, v j⟫ = 0) : |o.volumeForm v| = ∏ i : Fin n, ‖v i‖ := by
cases' n with n
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl <;> simp
haveI : FiniteDimensional ℝ E := .of_fact_finrank_eq_succ n
have hdim : finrank ℝ E = Fintype.card (Fin n.succ) := by simpa using _i.out
let b : OrthonormalBasis (Fin n.succ) ℝ E := gramSchmidtOrthonormalBasis hdim v
have hb : b.toBasis.det v = ∏ i, ⟪b i, v i⟫ := gramSchmidtOrthonormalBasis_det hdim v
rw [o.volumeForm_robust' b, hb, Finset.abs_prod]
by_cases h : ∃ i, v i = 0
· obtain ⟨i, hi⟩ := h
rw [Finset.prod_eq_zero (Finset.mem_univ i), Finset.prod_eq_zero (Finset.mem_univ i)] <;>
simp [hi]
push_neg at h
congr
ext i
have hb : b i = ‖v i‖⁻¹ • v i := gramSchmidtOrthonormalBasis_apply_of_orthogonal hdim hv (h i)
simp only [hb, inner_smul_left, real_inner_self_eq_norm_mul_norm, RCLike.conj_to_real]
rw [abs_of_nonneg]
· field_simp
· positivity
#align orientation.abs_volume_form_apply_of_pairwise_orthogonal Orientation.abs_volumeForm_apply_of_pairwise_orthogonal
/-- The output of the volume form of an oriented real inner product space `E` when evaluated on an
orthonormal basis is ±1. -/
theorem abs_volumeForm_apply_of_orthonormal (v : OrthonormalBasis (Fin n) ℝ E) :
|o.volumeForm v| = 1 := by
simpa [o.volumeForm_robust' v v] using congr_arg abs v.toBasis.det_self
#align orientation.abs_volume_form_apply_of_orthonormal Orientation.abs_volumeForm_apply_of_orthonormal
theorem volumeForm_map {F : Type*} [NormedAddCommGroup F] [InnerProductSpace ℝ F]
[Fact (finrank ℝ F = n)] (φ : E ≃ₗᵢ[ℝ] F) (x : Fin n → F) :
(Orientation.map (Fin n) φ.toLinearEquiv o).volumeForm x = o.volumeForm (φ.symm ∘ x) := by
cases' n with n
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl <;> simp
let e : OrthonormalBasis (Fin n.succ) ℝ E := o.finOrthonormalBasis n.succ_pos Fact.out
have he : e.toBasis.orientation = o :=
o.finOrthonormalBasis_orientation n.succ_pos Fact.out
have heφ : (e.map φ).toBasis.orientation = Orientation.map (Fin n.succ) φ.toLinearEquiv o := by
rw [← he]
exact e.toBasis.orientation_map φ.toLinearEquiv
rw [(Orientation.map (Fin n.succ) φ.toLinearEquiv o).volumeForm_robust (e.map φ) heφ]
rw [o.volumeForm_robust e he]
simp
#align orientation.volume_form_map Orientation.volumeForm_map
/-- The volume form is invariant under pullback by a positively-oriented isometric automorphism. -/
theorem volumeForm_comp_linearIsometryEquiv (φ : E ≃ₗᵢ[ℝ] E)
(hφ : 0 < LinearMap.det (φ.toLinearEquiv : E →ₗ[ℝ] E)) (x : Fin n → E) :
o.volumeForm (φ ∘ x) = o.volumeForm x := by
cases' n with n -- Porting note: need to explicitly prove `FiniteDimensional ℝ E`
· refine o.eq_or_eq_neg_of_isEmpty.elim ?_ ?_ <;> rintro rfl <;> simp
haveI : FiniteDimensional ℝ E := .of_fact_finrank_eq_succ n
convert o.volumeForm_map φ (φ ∘ x)
· symm
rwa [← o.map_eq_iff_det_pos φ.toLinearEquiv] at hφ
rw [_i.out, Fintype.card_fin]
· ext
simp
#align orientation.volume_form_comp_linear_isometry_equiv Orientation.volumeForm_comp_linearIsometryEquiv
end VolumeForm
end Orientation