Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit a143c38

Browse files
committed
refactor(linear_algebra/affine_space): allow empty affine subspaces (#3219)
When definitions of affine spaces and subspaces were added in #2816, there was some discussion of whether an affine subspace should be allowed to be empty. After further consideration of what lemmas need to be added to fill out the interface for affine subspaces, I've concluded that it does indeed make sense to allow empty affine subspaces, with `nonempty` hypotheses then added for those results that need them, to avoid artificial `nonempty` hypotheses for other results on affine spans and intersections of affine subspaces that don't depend on any way on affine subspaces being nonempty and can be more cleanly stated if they can be empty. Thus, change the definition to allow affine subspaces to be empty and remove the bundled `direction`. The new definition of `direction` (as the `vector_span` of the points in the subspace, i.e. the `submodule.span` of the `vsub_set` of the points) is the zero submodule for both empty affine subspaces and for those consisting of a single point (and it's proved that in the nonempty case it contains exactly the pairwise subtractions of points in the affine subspace). This doesn't generally add new lemmas beyond those used in reproving existing results (including what were previously the `add` and `sub` axioms for affine subspaces) with the new definitions. It also doesn't add the complete lattice structure for affine subspaces, just helps enable adding it later.
1 parent e250eb4 commit a143c38

File tree

2 files changed

+186
-89
lines changed

2 files changed

+186
-89
lines changed

src/algebra/add_torsor.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@ by rw [←vsub_vadd_eq_vsub_sub, vsub_vadd]
220220
/-- The pairwise differences of a set of points. -/
221221
def vsub_set (s : set P) : set G := {g | ∃ x ∈ s, ∃ y ∈ s, g = x -ᵥ y}
222222

223+
/-- Each pairwise difference is in the `vsub_set`. -/
224+
lemma vsub_mem_vsub_set {p1 p2 : P} {s : set P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) :
225+
(p1 -ᵥ p2) ∈ vsub_set G s :=
226+
⟨p1, hp1, p2, hp2, rfl⟩
227+
228+
/-- `vsub_set` is contained in `vsub_set` of a larger set. -/
229+
lemma vsub_set_mono {s1 s2 : set P} (h : s1 ⊆ s2) : vsub_set G s1 ⊆ vsub_set G s2 :=
230+
begin
231+
rintros v ⟨p1, hp1, p2, hp2, hv⟩,
232+
exact ⟨p1, set.mem_of_mem_of_subset hp1 h, p2, set.mem_of_mem_of_subset hp2 h, hv⟩
233+
end
234+
223235
@[simp] lemma vadd_vsub_vadd_cancel_right (v₁ v₂ : G) (p : P) :
224236
((v₁ +ᵥ p) -ᵥ (v₂ +ᵥ p) : G) = v₁ - v₂ :=
225237
by rw [vsub_vadd_eq_vsub_sub, vadd_vsub_assoc, vsub_self, add_zero]

src/linear_algebra/affine_space.lean

Lines changed: 174 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ points (via the definition of torsors requiring a nonempty type).
3535
3636
-/
3737

38+
open add_action
39+
open add_torsor
40+
3841
/-- `affine_space` is an abbreviation for `add_torsor` in the case
3942
where the group is a vector space, or more generally a module, but we
4043
omit the type classes `[ring k]` and `[module k V]` in the type
@@ -45,9 +48,6 @@ add_torsor V P
4548

4649
namespace affine_space
4750

48-
open add_action
49-
open add_torsor
50-
5151
variables (k : Type*) (V : Type*) {P : Type*} [ring k] [add_comm_group V] [module k V]
5252
variables [S : affine_space k V P]
5353
include S
@@ -56,16 +56,32 @@ include S
5656
of points. -/
5757
def vector_span (s : set P) : submodule k V := submodule.span k (vsub_set V s)
5858

59+
/-- The `vsub_set` lies within the `vector_span`. -/
60+
lemma vsub_set_subset_vector_span (s : set P) : vsub_set V s ⊆ vector_span k V s :=
61+
submodule.subset_span
62+
63+
/-- Each pairwise difference is in the `vector_span`. -/
64+
lemma vsub_mem_vector_span {s : set P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) :
65+
p1 -ᵥ p2 ∈ vector_span k V s :=
66+
begin
67+
rw ←submodule.mem_coe,
68+
exact set.mem_of_mem_of_subset (vsub_mem_vsub_set V hp1 hp2)
69+
(vsub_set_subset_vector_span k V s)
70+
end
71+
5972
/-- The points in the affine span of a (possibly empty) set of
60-
points. Use `affine_span` instead to get an `affine_subspace k V P`,
61-
if the set of points is known to be nonempty. -/
73+
points. Use `affine_span` instead to get an `affine_subspace k V P`. -/
6274
def span_points (s : set P) : set P :=
6375
{p | ∃ p1 ∈ s, ∃ v ∈ (vector_span k V s), p = v +ᵥ p1}
6476

6577
/-- A point in a set is in its affine span. -/
6678
lemma mem_span_points (p : P) (s : set P) : p ∈ s → p ∈ span_points k V s
6779
| hp := ⟨p, hp, 0, submodule.zero_mem _, (zero_vadd V p).symm⟩
6880

81+
/-- A set is contained in its `span_points`. -/
82+
lemma subset_span_points (s : set P) : s ⊆ span_points k V s :=
83+
λ p, mem_span_points k V p s
84+
6985
/-- The set of points in the affine span of a nonempty set of points
7086
is nonempty. -/
7187
lemma span_points_nonempty_of_nonempty {s : set P} :
@@ -96,19 +112,14 @@ begin
96112
rw ←neg_one_smul k v2,
97113
exact (vector_span k V s).smul_mem (-1 : k) hv2 },
98114
refine (vector_span k V s).add_mem _ hv1v2,
99-
unfold vector_span,
100-
change p1a -ᵥ p2a ∈ submodule.span k (vsub_set V s),
101-
have hp1p2 : p1a -ᵥ p2a ∈ vsub_set V s, { use [p1a, hp1a, p2a, hp2a] },
102-
have hp1p2s : vsub_set V s ⊆ submodule.span k (vsub_set V s) := submodule.subset_span,
103-
apply set.mem_of_mem_of_subset hp1p2 hp1p2s
115+
exact vsub_mem_vector_span k V hp1a hp2a
104116
end
105117

106118
end affine_space
107119

108-
namespace finset
120+
open affine_space
109121

110-
open add_action
111-
open add_torsor
122+
namespace finset
112123

113124
variables {k : Type*} (V : Type*) {P : Type*} [ring k] [add_comm_group V] [module k V]
114125
variables [S : affine_space k V P]
@@ -245,8 +256,6 @@ end finset
245256

246257
section affine_independent
247258

248-
open add_torsor
249-
250259
variables (k : Type*) (V : Type*) {P : Type*} [ring k] [add_comm_group V] [module k V]
251260
variables [affine_space k V P] {ι : Type*}
252261

@@ -314,18 +323,13 @@ end
314323

315324
end affine_independent
316325

317-
open add_torsor affine_space
318-
319326
/-- An `affine_subspace k V P` is a subset of an `affine_space k V P`
320-
that has an affine space structure induced by a corresponding subspace
321-
of the `module k V`. -/
327+
that, if not empty, has an affine space structure induced by a
328+
corresponding subspace of the `module k V`. -/
322329
structure affine_subspace (k : Type*) (V : Type*) (P : Type*) [ring k] [add_comm_group V]
323330
[module k V] [affine_space k V P] :=
324331
(carrier : set P)
325-
(direction : submodule k V)
326-
(nonempty : carrier.nonempty)
327-
(add : ∀ (p : P) (v : V), p ∈ carrier → v ∈ direction → v +ᵥ p ∈ carrier)
328-
(sub : ∀ (p1 p2 : P), p1 ∈ carrier → p2 ∈ carrier → p1 -ᵥ p2 ∈ direction)
332+
(smul_vsub_vadd_mem : ∀ (c : k) (p1 p2 p3 ∈ carrier), c • (p1 -ᵥ p2 : V) +ᵥ p3 ∈ carrier)
329333

330334
namespace affine_subspace
331335

@@ -345,16 +349,7 @@ iff.rfl
345349
/-- The whole affine space as a subspace of itself. -/
346350
def univ : affine_subspace k V P :=
347351
{ carrier := set.univ,
348-
direction := submodule.span k set.univ,
349-
nonempty := set.nonempty_iff_univ_nonempty.1 S.nonempty,
350-
add := λ p v hp hv, set.mem_univ _,
351-
sub := begin
352-
intros p1 p2 hp1 hp2,
353-
apply set.mem_bInter,
354-
intros x hx,
355-
rw set.mem_set_of_eq at hx,
356-
exact set.mem_of_mem_of_subset (set.mem_univ _) hx
357-
end }
352+
smul_vsub_vadd_mem := λ _ _ _ _ _ _ _, set.mem_univ _ }
358353

359354
/-- `univ`, coerced to a set, is the whole set of points. -/
360355
@[simp] lemma univ_coe : (univ k V P : set P) = set.univ :=
@@ -368,30 +363,93 @@ instance : inhabited (affine_subspace k V P) := ⟨univ k V P⟩
368363

369364
variables {k V P}
370365

366+
/-- The direction of an affine subspace is the submodule spanned by
367+
the pairwise differences of points. (Except in the case of an empty
368+
affine subspace, where the direction is the zero submodule, every
369+
vector in the direction is the difference of two points in the affine
370+
subspace.) -/
371+
def direction (s : affine_subspace k V P) : submodule k V := vector_span k V (s : set P)
372+
373+
/-- The direction equals the `vector_span`. -/
374+
lemma direction_eq_vector_span (s : affine_subspace k V P) :
375+
s.direction = vector_span k V (s : set P) :=
376+
rfl
377+
378+
/-- Alternative definition of the direction when the affine subspace
379+
is nonempty. This is defined so that the order on submodules (as used
380+
in the definition of `submodule.span`) can be used in the proof of
381+
`coe_direction_eq_vsub_set`, and is not intended to be used beyond
382+
that proof. -/
383+
def direction_of_nonempty {s : affine_subspace k V P} (h : (s : set P).nonempty) :
384+
submodule k V :=
385+
{ carrier := vsub_set V (s : set P),
386+
zero_mem' := begin
387+
cases h with p hp,
388+
exact (vsub_self V p) ▸ vsub_mem_vsub_set V hp hp
389+
end,
390+
add_mem' := begin
391+
intros a b ha hb,
392+
rcases ha with ⟨p1, hp1, p2, hp2, ha⟩,
393+
rcases hb with ⟨p3, hp3, p4, hp4, hb⟩,
394+
rw [ha, hb, ←vadd_vsub_assoc],
395+
refine vsub_mem_vsub_set V _ hp4,
396+
convert s.smul_vsub_vadd_mem 1 p1 p2 p3 hp1 hp2 hp3,
397+
rw one_smul
398+
end,
399+
smul_mem' := begin
400+
intros c v hv,
401+
rcases hv with ⟨p1, hp1, p2, hp2, hv⟩,
402+
rw [hv, ←vadd_vsub V (c • (p1 -ᵥ p2)) p2],
403+
refine vsub_mem_vsub_set V _ hp2,
404+
exact s.smul_vsub_vadd_mem c p1 p2 p2 hp1 hp2 hp2
405+
end }
406+
407+
/-- `direction_of_nonempty` gives the same submodule as
408+
`direction`. -/
409+
lemma direction_of_nonempty_eq_direction {s : affine_subspace k V P} (h : (s : set P).nonempty) :
410+
direction_of_nonempty h = s.direction :=
411+
le_antisymm (vsub_set_subset_vector_span k V s) (submodule.span_le.2 set.subset.rfl)
412+
413+
/-- The set of vectors in the direction of a nonempty affine subspace
414+
is given by `vsub_set`. -/
415+
lemma coe_direction_eq_vsub_set {s : affine_subspace k V P} (h : (s : set P).nonempty) :
416+
(s.direction : set V) = vsub_set V (s : set P) :=
417+
direction_of_nonempty_eq_direction h ▸ rfl
418+
419+
/-- A vector is in the direction of a nonempty affine subspace if and
420+
only if it is the subtraction of two vectors in the subspace. -/
421+
lemma mem_direction_iff_eq_vsub {s : affine_subspace k V P} (h : (s : set P).nonempty) (v : V) :
422+
v ∈ s.direction ↔ ∃ p1 ∈ s, ∃ p2 ∈ s, v = p1 -ᵥ p2 :=
423+
begin
424+
rw [←submodule.mem_coe, coe_direction_eq_vsub_set h],
425+
exact iff.rfl
426+
end
427+
428+
/-- Adding a vector in the direction to a point in the subspace
429+
produces a point in the subspace. -/
430+
lemma vadd_mem_of_mem_direction {s : affine_subspace k V P} {v : V} (hv : v ∈ s.direction) {p : P}
431+
(hp : p ∈ s) : v +ᵥ p ∈ s :=
432+
begin
433+
rw mem_direction_iff_eq_vsub ⟨p, hp⟩ at hv,
434+
rcases hv with ⟨p1, hp1, p2, hp2, hv⟩,
435+
rw hv,
436+
convert s.smul_vsub_vadd_mem 1 p1 p2 p hp1 hp2 hp,
437+
rw one_smul
438+
end
439+
440+
/-- Subtracting two points in the subspace produces a vector in the
441+
direction. -/
442+
lemma vsub_mem_direction {s : affine_subspace k V P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) :
443+
(p1 -ᵥ p2) ∈ s.direction :=
444+
vsub_mem_vector_span k V hp1 hp2
445+
371446
/-- Two affine subspaces are equal if they have the same points. -/
372447
@[ext] lemma ext {s1 s2 : affine_subspace k V P} (h : (s1 : set P) = s2) : s1 = s2 :=
373448
begin
374449
cases s1,
375450
cases s2,
376-
change s1_carrier = s2_carrier at h,
377451
congr,
378-
{ exact h },
379-
{ ext v,
380-
split,
381-
{ intro hv,
382-
have hm := s1_nonempty.some_mem,
383-
have hvp := s1_add s1_nonempty.some v hm hv,
384-
conv_rhs at hm { rw h },
385-
conv_rhs at hvp { rw h },
386-
rw ←vadd_vsub V v s1_nonempty.some,
387-
exact s2_sub _ _ hvp hm },
388-
{ intro hv,
389-
have hm := s2_nonempty.some_mem,
390-
have hvp := s2_add s2_nonempty.some v hm hv,
391-
conv_rhs at hm { rw ←h },
392-
conv_rhs at hvp { rw ←h },
393-
rw ←vadd_vsub V v s2_nonempty.some,
394-
exact s1_sub _ _ hvp hm } }
452+
exact h
395453
end
396454

397455
/-- Two affine subspaces with the same direction and nonempty
@@ -405,75 +463,102 @@ begin
405463
split,
406464
{ intro hp,
407465
rw ←vsub_vadd V p hn.some,
408-
refine s2.add _ _ hq2 _,
466+
refine vadd_mem_of_mem_direction _ hq2,
409467
rw ←hd,
410-
exact s1.sub _ _ hp hq1 },
468+
exact vsub_mem_direction hp hq1 },
411469
{ intro hp,
412470
rw ←vsub_vadd V p hn.some,
413-
refine s1.add _ _ hq1 _,
471+
refine vadd_mem_of_mem_direction _ hq1,
414472
rw hd,
415-
exact s2.sub _ _ hp hq2 }
473+
exact vsub_mem_direction hp hq2 }
416474
end
417475

418476
/-- Construct an affine subspace from a point and a direction. -/
419-
def mk_of_point_of_direction (p : P) (direction : submodule k V) : affine_subspace k V P :=
477+
def mk' (p : P) (direction : submodule k V) : affine_subspace k V P :=
420478
{ carrier := {q | ∃ v ∈ direction, q = v +ᵥ p},
421-
direction := direction,
422-
nonempty := ⟨p, ⟨0, ⟨direction.zero_mem, (add_action.zero_vadd _ _).symm⟩⟩⟩,
423-
add := λ p2 v hp2 hv, begin
424-
rcases hp2 with ⟨v2, hv2, hp2⟩,
425-
use [v + v2, direction.add_mem hv hv2],
426-
rw [←add_action.vadd_assoc, hp2]
427-
end,
428-
sub := λ p1 p2 hp1 hp2, begin
479+
smul_vsub_vadd_mem := λ c p1 p2 p3 hp1 hp2 hp3, begin
429480
rcases hp1 with ⟨v1, hv1, hp1⟩,
430481
rcases hp2 with ⟨v2, hv2, hp2⟩,
431-
rw [hp1, hp2, vadd_vsub_vadd_cancel_right],
432-
exact direction.sub_mem hv1 hv2
482+
rcases hp3 with ⟨v3, hv3, hp3⟩,
483+
use [c • (v1 - v2) + v3,
484+
direction.add_mem (direction.smul_mem c (direction.sub_mem hv1 hv2)) hv3],
485+
simp [hp1, hp2, hp3, vadd_assoc]
433486
end }
434487

435-
/-- The direction of an affine space constructed from a point and a
436-
direction. -/
437-
@[simp] lemma direction_mk_of_point_of_direction (p : P) (direction : submodule k V) :
438-
(mk_of_point_of_direction p direction).direction = direction :=
439-
rfl
440-
441488
/-- An affine space constructed from a point and a direction contains
442489
that point. -/
443-
lemma mem_mk_of_point_of_direction (p : P) (direction : submodule k V) :
444-
p ∈ mk_of_point_of_direction p direction :=
490+
lemma self_mem_mk' (p : P) (direction : submodule k V) :
491+
p ∈ mk' p direction :=
445492
0, ⟨direction.zero_mem, (add_action.zero_vadd _ _).symm⟩⟩
446493

494+
/-- An affine space constructed from a point and a direction contains
495+
the result of adding a vector in that direction to that point. -/
496+
lemma vadd_mem_mk' {v : V} (p : P) {direction : submodule k V} (hv : v ∈ direction) :
497+
v +ᵥ p ∈ mk' p direction :=
498+
⟨v, hv, rfl⟩
499+
500+
/-- An affine space constructed from a point and a direction is
501+
nonempty. -/
502+
lemma mk'_nonempty (p : P) (direction : submodule k V) : (mk' p direction : set P).nonempty :=
503+
⟨p, self_mem_mk' p direction⟩
504+
505+
/-- The direction of an affine space constructed from a point and a
506+
direction. -/
507+
@[simp] lemma direction_mk' (p : P) (direction : submodule k V) :
508+
(mk' p direction).direction = direction :=
509+
begin
510+
ext v,
511+
rw mem_direction_iff_eq_vsub (mk'_nonempty _ _),
512+
split,
513+
{ rintros ⟨p1, ⟨v1, hv1, hp1⟩, p2, ⟨v2, hv2, hp2⟩, hv⟩,
514+
rw [hv, hp1, hp2, vadd_vsub_vadd_cancel_right],
515+
exact direction.sub_mem hv1 hv2 },
516+
{ exact λ hv, ⟨v +ᵥ p, vadd_mem_mk' _ hv, p,
517+
self_mem_mk' _ _, (vadd_vsub _ _ _).symm⟩ }
518+
end
519+
447520
/-- Constructing an affine subspace from a point in a subspace and
448521
that subspace's direction yields the original subspace. -/
449-
@[simp] lemma mk_of_point_of_direction_eq {s : affine_subspace k V P} {p : P} (hp : p ∈ s) :
450-
mk_of_point_of_direction p s.direction = s :=
451-
ext_of_direction_eq rfl ⟨p, set.mem_inter (mem_mk_of_point_of_direction _ _) hp⟩
522+
@[simp] lemma mk'_eq {s : affine_subspace k V P} {p : P} (hp : p ∈ s) : mk' p s.direction = s :=
523+
ext_of_direction_eq (direction_mk' p s.direction)
524+
⟨p, set.mem_inter (self_mem_mk' _ _) hp⟩
452525

453526
end affine_subspace
454527

455528
section affine_span
456529

457-
variables (k : Type*) (V : Type*) (P : Type*) [ring k] [add_comm_group V] [module k V]
530+
variables (k : Type*) (V : Type*) {P : Type*} [ring k] [add_comm_group V] [module k V]
458531
[affine_space k V P]
459532

460-
/-- The affine span of a nonempty set of points is the smallest affine
461-
subspace containing those points. (Actually defined here in terms of
462-
spans in modules.) -/
463-
def affine_span (s : set P) (h : s.nonempty) : affine_subspace k V P :=
533+
/-- The affine span of a set of points is the smallest affine subspace
534+
containing those points. (Actually defined here in terms of spans in
535+
modules.) -/
536+
def affine_span (s : set P) : affine_subspace k V P :=
464537
{ carrier := span_points k V s,
465-
direction := vector_span k V s,
466-
nonempty := span_points_nonempty_of_nonempty k V h,
467-
add := λ p v hp hv, vadd_mem_span_points_of_mem_span_points_of_mem_vector_span k V hp hv,
468-
sub := λ p1 p2 hp1 hp2, vsub_mem_vector_span_of_mem_span_points_of_mem_span_points k V hp1 hp2 }
538+
smul_vsub_vadd_mem := λ c p1 p2 p3 hp1 hp2 hp3,
539+
vadd_mem_span_points_of_mem_span_points_of_mem_vector_span k V hp3
540+
((vector_span k V s).smul_mem c
541+
(vsub_mem_vector_span_of_mem_span_points_of_mem_span_points k V hp1 hp2)) }
469542

470543
/-- The affine span, converted to a set, is `span_points`. -/
471-
@[simp] lemma affine_span_coe (s : set P) (h : s.nonempty) :
472-
(affine_span k V P s h : set P) = span_points k V s :=
544+
@[simp] lemma coe_affine_span (s : set P) :
545+
(affine_span k V s : set P) = span_points k V s :=
473546
rfl
474547

548+
/-- The direction of the affine span is the `vector_span`. -/
549+
lemma direction_affine_span (s : set P) : (affine_span k V s).direction = vector_span k V s :=
550+
begin
551+
apply le_antisymm,
552+
{ refine submodule.span_le.2 _,
553+
rintros v ⟨p1, ⟨p2, hp2, v1, hv1, hp1⟩, p3, ⟨p4, hp4, v2, hv2, hp3⟩, hv⟩,
554+
rw [hv, hp1, hp3, vsub_vadd_eq_vsub_sub, vadd_vsub_assoc, submodule.mem_coe],
555+
exact (vector_span k V s).sub_mem ((vector_span k V s).add_mem hv1
556+
(vsub_mem_vector_span k V hp2 hp4)) hv2 },
557+
{ exact submodule.span_mono (vsub_set_mono V (subset_span_points k V s)) }
558+
end
559+
475560
/-- A point in a set is in its affine span. -/
476-
lemma affine_span_mem (p : P) (s : set P) (hp : p ∈ s) : p ∈ affine_span k V P s ⟨p, hp⟩ :=
561+
lemma mem_affine_span {p : P} {s : set P} (hp : p ∈ s) : p ∈ affine_span k V s :=
477562
mem_span_points k V p s hp
478563

479564
end affine_span

0 commit comments

Comments
 (0)