/
AffineSubspace.lean
1891 lines (1580 loc) · 86.3 KB
/
AffineSubspace.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
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/-
Copyright (c) 2020 Joseph Myers. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joseph Myers
-/
import Mathlib.LinearAlgebra.AffineSpace.AffineEquiv
#align_import linear_algebra.affine_space.affine_subspace from "leanprover-community/mathlib"@"e96bdfbd1e8c98a09ff75f7ac6204d142debc840"
/-!
# Affine spaces
This file defines affine subspaces (over modules) and the affine span of a set of points.
## Main definitions
* `AffineSubspace k P` is the type of affine subspaces. Unlike affine spaces, affine subspaces are
allowed to be empty, and lemmas that do not apply to empty affine subspaces have `Nonempty`
hypotheses. There is a `CompleteLattice` structure on affine subspaces.
* `AffineSubspace.direction` gives the `Submodule` spanned by the pairwise differences of points
in an `AffineSubspace`. There are various lemmas relating to the set of vectors in the
`direction`, and relating the lattice structure on affine subspaces to that on their directions.
* `AffineSubspace.parallel`, notation `∥`, gives the property of two affine subspaces being
parallel (one being a translate of the other).
* `affineSpan` gives the affine subspace spanned by a set of points, with `vectorSpan` giving its
direction. The `affineSpan` is defined in terms of `spanPoints`, which gives an explicit
description of the points contained in the affine span; `spanPoints` itself should generally only
be used when that description is required, with `affineSpan` being the main definition for other
purposes. Two other descriptions of the affine span are proved equivalent: it is the `sInf` of
affine subspaces containing the points, and (if `[Nontrivial k]`) it contains exactly those points
that are affine combinations of points in the given set.
## Implementation notes
`outParam` is used in the definition of `AddTorsor V P` to make `V` an implicit argument (deduced
from `P`) in most cases. As for modules, `k` is an explicit argument rather than implied by `P` or
`V`.
This file only provides purely algebraic definitions and results. Those depending on analysis or
topology are defined elsewhere; see `Analysis.NormedSpace.AddTorsor` and `Topology.Algebra.Affine`.
## References
* https://en.wikipedia.org/wiki/Affine_space
* https://en.wikipedia.org/wiki/Principal_homogeneous_space
-/
noncomputable section
open BigOperators Affine
open Set
section
variable (k : Type*) {V : Type*} {P : Type*} [Ring k] [AddCommGroup V] [Module k V]
variable [AffineSpace V P]
/-- The submodule spanning the differences of a (possibly empty) set of points. -/
def vectorSpan (s : Set P) : Submodule k V :=
Submodule.span k (s -ᵥ s)
#align vector_span vectorSpan
/-- The definition of `vectorSpan`, for rewriting. -/
theorem vectorSpan_def (s : Set P) : vectorSpan k s = Submodule.span k (s -ᵥ s) :=
rfl
#align vector_span_def vectorSpan_def
/-- `vectorSpan` is monotone. -/
theorem vectorSpan_mono {s₁ s₂ : Set P} (h : s₁ ⊆ s₂) : vectorSpan k s₁ ≤ vectorSpan k s₂ :=
Submodule.span_mono (vsub_self_mono h)
#align vector_span_mono vectorSpan_mono
variable (P)
/-- The `vectorSpan` of the empty set is `⊥`. -/
@[simp]
theorem vectorSpan_empty : vectorSpan k (∅ : Set P) = (⊥ : Submodule k V) := by
rw [vectorSpan_def, vsub_empty, Submodule.span_empty]
#align vector_span_empty vectorSpan_empty
variable {P}
/-- The `vectorSpan` of a single point is `⊥`. -/
@[simp]
theorem vectorSpan_singleton (p : P) : vectorSpan k ({p} : Set P) = ⊥ := by simp [vectorSpan_def]
#align vector_span_singleton vectorSpan_singleton
/-- The `s -ᵥ s` lies within the `vectorSpan k s`. -/
theorem vsub_set_subset_vectorSpan (s : Set P) : s -ᵥ s ⊆ ↑(vectorSpan k s) :=
Submodule.subset_span
#align vsub_set_subset_vector_span vsub_set_subset_vectorSpan
/-- Each pairwise difference is in the `vectorSpan`. -/
theorem vsub_mem_vectorSpan {s : Set P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) :
p1 -ᵥ p2 ∈ vectorSpan k s :=
vsub_set_subset_vectorSpan k s (vsub_mem_vsub hp1 hp2)
#align vsub_mem_vector_span vsub_mem_vectorSpan
/-- The points in the affine span of a (possibly empty) set of points. Use `affineSpan` instead to
get an `AffineSubspace k P`. -/
def spanPoints (s : Set P) : Set P :=
{ p | ∃ p1 ∈ s, ∃ v ∈ vectorSpan k s, p = v +ᵥ p1 }
#align span_points spanPoints
/-- A point in a set is in its affine span. -/
theorem mem_spanPoints (p : P) (s : Set P) : p ∈ s → p ∈ spanPoints k s
| hp => ⟨p, hp, 0, Submodule.zero_mem _, (zero_vadd V p).symm⟩
#align mem_span_points mem_spanPoints
/-- A set is contained in its `spanPoints`. -/
theorem subset_spanPoints (s : Set P) : s ⊆ spanPoints k s := fun p => mem_spanPoints k p s
#align subset_span_points subset_spanPoints
/-- The `spanPoints` of a set is nonempty if and only if that set is. -/
@[simp]
theorem spanPoints_nonempty (s : Set P) : (spanPoints k s).Nonempty ↔ s.Nonempty := by
constructor
· contrapose
rw [Set.not_nonempty_iff_eq_empty, Set.not_nonempty_iff_eq_empty]
intro h
simp [h, spanPoints]
· exact fun h => h.mono (subset_spanPoints _ _)
#align span_points_nonempty spanPoints_nonempty
/-- Adding a point in the affine span and a vector in the spanning submodule produces a point in the
affine span. -/
theorem vadd_mem_spanPoints_of_mem_spanPoints_of_mem_vectorSpan {s : Set P} {p : P} {v : V}
(hp : p ∈ spanPoints k s) (hv : v ∈ vectorSpan k s) : v +ᵥ p ∈ spanPoints k s := by
rcases hp with ⟨p2, ⟨hp2, ⟨v2, ⟨hv2, hv2p⟩⟩⟩⟩
rw [hv2p, vadd_vadd]
exact ⟨p2, hp2, v + v2, (vectorSpan k s).add_mem hv hv2, rfl⟩
#align vadd_mem_span_points_of_mem_span_points_of_mem_vector_span vadd_mem_spanPoints_of_mem_spanPoints_of_mem_vectorSpan
/-- Subtracting two points in the affine span produces a vector in the spanning submodule. -/
theorem vsub_mem_vectorSpan_of_mem_spanPoints_of_mem_spanPoints {s : Set P} {p1 p2 : P}
(hp1 : p1 ∈ spanPoints k s) (hp2 : p2 ∈ spanPoints k s) : p1 -ᵥ p2 ∈ vectorSpan k s := by
rcases hp1 with ⟨p1a, ⟨hp1a, ⟨v1, ⟨hv1, hv1p⟩⟩⟩⟩
rcases hp2 with ⟨p2a, ⟨hp2a, ⟨v2, ⟨hv2, hv2p⟩⟩⟩⟩
rw [hv1p, hv2p, vsub_vadd_eq_vsub_sub (v1 +ᵥ p1a), vadd_vsub_assoc, add_comm, add_sub_assoc]
have hv1v2 : v1 - v2 ∈ vectorSpan k s := (vectorSpan k s).sub_mem hv1 hv2
refine' (vectorSpan k s).add_mem _ hv1v2
exact vsub_mem_vectorSpan k hp1a hp2a
#align vsub_mem_vector_span_of_mem_span_points_of_mem_span_points vsub_mem_vectorSpan_of_mem_spanPoints_of_mem_spanPoints
end
/-- An `AffineSubspace k P` is a subset of an `AffineSpace V P` that, if not empty, has an affine
space structure induced by a corresponding subspace of the `Module k V`. -/
structure AffineSubspace (k : Type*) {V : Type*} (P : Type*) [Ring k] [AddCommGroup V]
[Module k V] [AffineSpace V P] where
/-- The affine subspace seen as a subset. -/
carrier : Set P
smul_vsub_vadd_mem :
∀ (c : k) {p1 p2 p3 : P},
p1 ∈ carrier → p2 ∈ carrier → p3 ∈ carrier → c • (p1 -ᵥ p2 : V) +ᵥ p3 ∈ carrier
#align affine_subspace AffineSubspace
namespace Submodule
variable {k V : Type*} [Ring k] [AddCommGroup V] [Module k V]
/-- Reinterpret `p : Submodule k V` as an `AffineSubspace k V`. -/
def toAffineSubspace (p : Submodule k V) : AffineSubspace k V where
carrier := p
smul_vsub_vadd_mem _ _ _ _ h₁ h₂ h₃ := p.add_mem (p.smul_mem _ (p.sub_mem h₁ h₂)) h₃
#align submodule.to_affine_subspace Submodule.toAffineSubspace
end Submodule
namespace AffineSubspace
variable (k : Type*) {V : Type*} (P : Type*) [Ring k] [AddCommGroup V] [Module k V]
[AffineSpace V P]
instance : SetLike (AffineSubspace k P) P where
coe := carrier
coe_injective' p q _ := by cases p; cases q; congr
/-- A point is in an affine subspace coerced to a set if and only if it is in that affine
subspace. -/
-- Porting note: removed `simp`, proof is `simp only [SetLike.mem_coe]`
theorem mem_coe (p : P) (s : AffineSubspace k P) : p ∈ (s : Set P) ↔ p ∈ s :=
Iff.rfl
#align affine_subspace.mem_coe AffineSubspace.mem_coe
variable {k P}
/-- The direction of an affine subspace is the submodule spanned by
the pairwise differences of points. (Except in the case of an empty
affine subspace, where the direction is the zero submodule, every
vector in the direction is the difference of two points in the affine
subspace.) -/
def direction (s : AffineSubspace k P) : Submodule k V :=
vectorSpan k (s : Set P)
#align affine_subspace.direction AffineSubspace.direction
/-- The direction equals the `vectorSpan`. -/
theorem direction_eq_vectorSpan (s : AffineSubspace k P) : s.direction = vectorSpan k (s : Set P) :=
rfl
#align affine_subspace.direction_eq_vector_span AffineSubspace.direction_eq_vectorSpan
/-- Alternative definition of the direction when the affine subspace is nonempty. This is defined so
that the order on submodules (as used in the definition of `Submodule.span`) can be used in the
proof of `coe_direction_eq_vsub_set`, and is not intended to be used beyond that proof. -/
def directionOfNonempty {s : AffineSubspace k P} (h : (s : Set P).Nonempty) : Submodule k V where
carrier := (s : Set P) -ᵥ s
zero_mem' := by
cases' h with p hp
exact vsub_self p ▸ vsub_mem_vsub hp hp
add_mem' := by
rintro _ _ ⟨p1, hp1, p2, hp2, rfl⟩ ⟨p3, hp3, p4, hp4, rfl⟩
rw [← vadd_vsub_assoc]
refine' vsub_mem_vsub _ hp4
convert s.smul_vsub_vadd_mem 1 hp1 hp2 hp3
rw [one_smul]
smul_mem' := by
rintro c _ ⟨p1, hp1, p2, hp2, rfl⟩
rw [← vadd_vsub (c • (p1 -ᵥ p2)) p2]
refine' vsub_mem_vsub _ hp2
exact s.smul_vsub_vadd_mem c hp1 hp2 hp2
#align affine_subspace.direction_of_nonempty AffineSubspace.directionOfNonempty
/-- `direction_of_nonempty` gives the same submodule as `direction`. -/
theorem directionOfNonempty_eq_direction {s : AffineSubspace k P} (h : (s : Set P).Nonempty) :
directionOfNonempty h = s.direction := by
refine le_antisymm ?_ (Submodule.span_le.2 Set.Subset.rfl)
rw [← SetLike.coe_subset_coe, directionOfNonempty, direction, Submodule.coe_set_mk,
AddSubmonoid.coe_set_mk]
exact vsub_set_subset_vectorSpan k _
#align affine_subspace.direction_of_nonempty_eq_direction AffineSubspace.directionOfNonempty_eq_direction
/-- The set of vectors in the direction of a nonempty affine subspace is given by `vsub_set`. -/
theorem coe_direction_eq_vsub_set {s : AffineSubspace k P} (h : (s : Set P).Nonempty) :
(s.direction : Set V) = (s : Set P) -ᵥ s :=
directionOfNonempty_eq_direction h ▸ rfl
#align affine_subspace.coe_direction_eq_vsub_set AffineSubspace.coe_direction_eq_vsub_set
/-- A vector is in the direction of a nonempty affine subspace if and only if it is the subtraction
of two vectors in the subspace. -/
theorem mem_direction_iff_eq_vsub {s : AffineSubspace k P} (h : (s : Set P).Nonempty) (v : V) :
v ∈ s.direction ↔ ∃ p1 ∈ s, ∃ p2 ∈ s, v = p1 -ᵥ p2 := by
rw [← SetLike.mem_coe, coe_direction_eq_vsub_set h, Set.mem_vsub]
simp only [SetLike.mem_coe, eq_comm]
#align affine_subspace.mem_direction_iff_eq_vsub AffineSubspace.mem_direction_iff_eq_vsub
/-- Adding a vector in the direction to a point in the subspace produces a point in the
subspace. -/
theorem vadd_mem_of_mem_direction {s : AffineSubspace k P} {v : V} (hv : v ∈ s.direction) {p : P}
(hp : p ∈ s) : v +ᵥ p ∈ s := by
rw [mem_direction_iff_eq_vsub ⟨p, hp⟩] at hv
rcases hv with ⟨p1, hp1, p2, hp2, hv⟩
rw [hv]
convert s.smul_vsub_vadd_mem 1 hp1 hp2 hp
rw [one_smul]
exact s.mem_coe k P _
#align affine_subspace.vadd_mem_of_mem_direction AffineSubspace.vadd_mem_of_mem_direction
/-- Subtracting two points in the subspace produces a vector in the direction. -/
theorem vsub_mem_direction {s : AffineSubspace k P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) :
p1 -ᵥ p2 ∈ s.direction :=
vsub_mem_vectorSpan k hp1 hp2
#align affine_subspace.vsub_mem_direction AffineSubspace.vsub_mem_direction
/-- Adding a vector to a point in a subspace produces a point in the subspace if and only if the
vector is in the direction. -/
theorem vadd_mem_iff_mem_direction {s : AffineSubspace k P} (v : V) {p : P} (hp : p ∈ s) :
v +ᵥ p ∈ s ↔ v ∈ s.direction :=
⟨fun h => by simpa using vsub_mem_direction h hp, fun h => vadd_mem_of_mem_direction h hp⟩
#align affine_subspace.vadd_mem_iff_mem_direction AffineSubspace.vadd_mem_iff_mem_direction
/-- Adding a vector in the direction to a point produces a point in the subspace if and only if
the original point is in the subspace. -/
theorem vadd_mem_iff_mem_of_mem_direction {s : AffineSubspace k P} {v : V} (hv : v ∈ s.direction)
{p : P} : v +ᵥ p ∈ s ↔ p ∈ s := by
refine' ⟨fun h => _, fun h => vadd_mem_of_mem_direction hv h⟩
convert vadd_mem_of_mem_direction (Submodule.neg_mem _ hv) h
simp
#align affine_subspace.vadd_mem_iff_mem_of_mem_direction AffineSubspace.vadd_mem_iff_mem_of_mem_direction
/-- Given a point in an affine subspace, the set of vectors in its direction equals the set of
vectors subtracting that point on the right. -/
theorem coe_direction_eq_vsub_set_right {s : AffineSubspace k P} {p : P} (hp : p ∈ s) :
(s.direction : Set V) = (· -ᵥ p) '' s := by
rw [coe_direction_eq_vsub_set ⟨p, hp⟩]
refine' le_antisymm _ _
· rintro v ⟨p1, hp1, p2, hp2, rfl⟩
exact ⟨p1 -ᵥ p2 +ᵥ p, vadd_mem_of_mem_direction (vsub_mem_direction hp1 hp2) hp, vadd_vsub _ _⟩
· rintro v ⟨p2, hp2, rfl⟩
exact ⟨p2, hp2, p, hp, rfl⟩
#align affine_subspace.coe_direction_eq_vsub_set_right AffineSubspace.coe_direction_eq_vsub_set_right
/-- Given a point in an affine subspace, the set of vectors in its direction equals the set of
vectors subtracting that point on the left. -/
theorem coe_direction_eq_vsub_set_left {s : AffineSubspace k P} {p : P} (hp : p ∈ s) :
(s.direction : Set V) = (p -ᵥ ·) '' s := by
ext v
rw [SetLike.mem_coe, ← Submodule.neg_mem_iff, ← SetLike.mem_coe,
coe_direction_eq_vsub_set_right hp, Set.mem_image, Set.mem_image]
conv_lhs =>
congr
ext
rw [← neg_vsub_eq_vsub_rev, neg_inj]
#align affine_subspace.coe_direction_eq_vsub_set_left AffineSubspace.coe_direction_eq_vsub_set_left
/-- Given a point in an affine subspace, a vector is in its direction if and only if it results from
subtracting that point on the right. -/
theorem mem_direction_iff_eq_vsub_right {s : AffineSubspace k P} {p : P} (hp : p ∈ s) (v : V) :
v ∈ s.direction ↔ ∃ p2 ∈ s, v = p2 -ᵥ p := by
rw [← SetLike.mem_coe, coe_direction_eq_vsub_set_right hp]
exact ⟨fun ⟨p2, hp2, hv⟩ => ⟨p2, hp2, hv.symm⟩, fun ⟨p2, hp2, hv⟩ => ⟨p2, hp2, hv.symm⟩⟩
#align affine_subspace.mem_direction_iff_eq_vsub_right AffineSubspace.mem_direction_iff_eq_vsub_right
/-- Given a point in an affine subspace, a vector is in its direction if and only if it results from
subtracting that point on the left. -/
theorem mem_direction_iff_eq_vsub_left {s : AffineSubspace k P} {p : P} (hp : p ∈ s) (v : V) :
v ∈ s.direction ↔ ∃ p2 ∈ s, v = p -ᵥ p2 := by
rw [← SetLike.mem_coe, coe_direction_eq_vsub_set_left hp]
exact ⟨fun ⟨p2, hp2, hv⟩ => ⟨p2, hp2, hv.symm⟩, fun ⟨p2, hp2, hv⟩ => ⟨p2, hp2, hv.symm⟩⟩
#align affine_subspace.mem_direction_iff_eq_vsub_left AffineSubspace.mem_direction_iff_eq_vsub_left
/-- Given a point in an affine subspace, a result of subtracting that point on the right is in the
direction if and only if the other point is in the subspace. -/
theorem vsub_right_mem_direction_iff_mem {s : AffineSubspace k P} {p : P} (hp : p ∈ s) (p2 : P) :
p2 -ᵥ p ∈ s.direction ↔ p2 ∈ s := by
rw [mem_direction_iff_eq_vsub_right hp]
simp
#align affine_subspace.vsub_right_mem_direction_iff_mem AffineSubspace.vsub_right_mem_direction_iff_mem
/-- Given a point in an affine subspace, a result of subtracting that point on the left is in the
direction if and only if the other point is in the subspace. -/
theorem vsub_left_mem_direction_iff_mem {s : AffineSubspace k P} {p : P} (hp : p ∈ s) (p2 : P) :
p -ᵥ p2 ∈ s.direction ↔ p2 ∈ s := by
rw [mem_direction_iff_eq_vsub_left hp]
simp
#align affine_subspace.vsub_left_mem_direction_iff_mem AffineSubspace.vsub_left_mem_direction_iff_mem
/-- Two affine subspaces are equal if they have the same points. -/
theorem coe_injective : Function.Injective ((↑) : AffineSubspace k P → Set P) :=
SetLike.coe_injective
#align affine_subspace.coe_injective AffineSubspace.coe_injective
@[ext]
theorem ext {p q : AffineSubspace k P} (h : ∀ x, x ∈ p ↔ x ∈ q) : p = q :=
SetLike.ext h
#align affine_subspace.ext AffineSubspace.ext
-- Porting note: removed `simp`, proof is `simp only [SetLike.ext'_iff]`
theorem ext_iff (s₁ s₂ : AffineSubspace k P) : (s₁ : Set P) = s₂ ↔ s₁ = s₂ :=
SetLike.ext'_iff.symm
#align affine_subspace.ext_iff AffineSubspace.ext_iff
/-- Two affine subspaces with the same direction and nonempty intersection are equal. -/
theorem ext_of_direction_eq {s1 s2 : AffineSubspace k P} (hd : s1.direction = s2.direction)
(hn : ((s1 : Set P) ∩ s2).Nonempty) : s1 = s2 := by
ext p
have hq1 := Set.mem_of_mem_inter_left hn.some_mem
have hq2 := Set.mem_of_mem_inter_right hn.some_mem
constructor
· intro hp
rw [← vsub_vadd p hn.some]
refine' vadd_mem_of_mem_direction _ hq2
rw [← hd]
exact vsub_mem_direction hp hq1
· intro hp
rw [← vsub_vadd p hn.some]
refine' vadd_mem_of_mem_direction _ hq1
rw [hd]
exact vsub_mem_direction hp hq2
#align affine_subspace.ext_of_direction_eq AffineSubspace.ext_of_direction_eq
-- See note [reducible non instances]
/-- This is not an instance because it loops with `AddTorsor.nonempty`. -/
@[reducible]
def toAddTorsor (s : AffineSubspace k P) [Nonempty s] : AddTorsor s.direction s where
vadd a b := ⟨(a : V) +ᵥ (b : P), vadd_mem_of_mem_direction a.2 b.2⟩
zero_vadd := fun a => by
ext
exact zero_vadd _ _
add_vadd a b c := by
ext
apply add_vadd
vsub a b := ⟨(a : P) -ᵥ (b : P), (vsub_left_mem_direction_iff_mem a.2 _).mpr b.2⟩
vsub_vadd' a b := by
ext
apply AddTorsor.vsub_vadd'
vadd_vsub' a b := by
ext
apply AddTorsor.vadd_vsub'
#align affine_subspace.to_add_torsor AffineSubspace.toAddTorsor
attribute [local instance] toAddTorsor
@[simp, norm_cast]
theorem coe_vsub (s : AffineSubspace k P) [Nonempty s] (a b : s) : ↑(a -ᵥ b) = (a : P) -ᵥ (b : P) :=
rfl
#align affine_subspace.coe_vsub AffineSubspace.coe_vsub
@[simp, norm_cast]
theorem coe_vadd (s : AffineSubspace k P) [Nonempty s] (a : s.direction) (b : s) :
↑(a +ᵥ b) = (a : V) +ᵥ (b : P) :=
rfl
#align affine_subspace.coe_vadd AffineSubspace.coe_vadd
/-- Embedding of an affine subspace to the ambient space, as an affine map. -/
protected def subtype (s : AffineSubspace k P) [Nonempty s] : s →ᵃ[k] P where
toFun := (↑)
linear := s.direction.subtype
map_vadd' _ _ := rfl
#align affine_subspace.subtype AffineSubspace.subtype
@[simp]
theorem subtype_linear (s : AffineSubspace k P) [Nonempty s] :
s.subtype.linear = s.direction.subtype := rfl
#align affine_subspace.subtype_linear AffineSubspace.subtype_linear
theorem subtype_apply (s : AffineSubspace k P) [Nonempty s] (p : s) : s.subtype p = p :=
rfl
#align affine_subspace.subtype_apply AffineSubspace.subtype_apply
@[simp]
theorem coeSubtype (s : AffineSubspace k P) [Nonempty s] : (s.subtype : s → P) = ((↑) : s → P) :=
rfl
#align affine_subspace.coe_subtype AffineSubspace.coeSubtype
theorem injective_subtype (s : AffineSubspace k P) [Nonempty s] : Function.Injective s.subtype :=
Subtype.coe_injective
#align affine_subspace.injective_subtype AffineSubspace.injective_subtype
/-- Two affine subspaces with nonempty intersection are equal if and only if their directions are
equal. -/
theorem eq_iff_direction_eq_of_mem {s₁ s₂ : AffineSubspace k P} {p : P} (h₁ : p ∈ s₁)
(h₂ : p ∈ s₂) : s₁ = s₂ ↔ s₁.direction = s₂.direction :=
⟨fun h => h ▸ rfl, fun h => ext_of_direction_eq h ⟨p, h₁, h₂⟩⟩
#align affine_subspace.eq_iff_direction_eq_of_mem AffineSubspace.eq_iff_direction_eq_of_mem
/-- Construct an affine subspace from a point and a direction. -/
def mk' (p : P) (direction : Submodule k V) : AffineSubspace k P where
carrier := { q | ∃ v ∈ direction, q = v +ᵥ p }
smul_vsub_vadd_mem c p1 p2 p3 hp1 hp2 hp3 := by
rcases hp1 with ⟨v1, hv1, hp1⟩
rcases hp2 with ⟨v2, hv2, hp2⟩
rcases hp3 with ⟨v3, hv3, hp3⟩
use c • (v1 - v2) + v3, direction.add_mem (direction.smul_mem c (direction.sub_mem hv1 hv2)) hv3
simp [hp1, hp2, hp3, vadd_vadd]
#align affine_subspace.mk' AffineSubspace.mk'
/-- An affine subspace constructed from a point and a direction contains that point. -/
theorem self_mem_mk' (p : P) (direction : Submodule k V) : p ∈ mk' p direction :=
⟨0, ⟨direction.zero_mem, (zero_vadd _ _).symm⟩⟩
#align affine_subspace.self_mem_mk' AffineSubspace.self_mem_mk'
/-- An affine subspace constructed from a point and a direction contains the result of adding a
vector in that direction to that point. -/
theorem vadd_mem_mk' {v : V} (p : P) {direction : Submodule k V} (hv : v ∈ direction) :
v +ᵥ p ∈ mk' p direction :=
⟨v, hv, rfl⟩
#align affine_subspace.vadd_mem_mk' AffineSubspace.vadd_mem_mk'
/-- An affine subspace constructed from a point and a direction is nonempty. -/
theorem mk'_nonempty (p : P) (direction : Submodule k V) : (mk' p direction : Set P).Nonempty :=
⟨p, self_mem_mk' p direction⟩
#align affine_subspace.mk'_nonempty AffineSubspace.mk'_nonempty
/-- The direction of an affine subspace constructed from a point and a direction. -/
@[simp]
theorem direction_mk' (p : P) (direction : Submodule k V) :
(mk' p direction).direction = direction := by
ext v
rw [mem_direction_iff_eq_vsub (mk'_nonempty _ _)]
constructor
· rintro ⟨p1, ⟨v1, hv1, hp1⟩, p2, ⟨v2, hv2, hp2⟩, hv⟩
rw [hv, hp1, hp2, vadd_vsub_vadd_cancel_right]
exact direction.sub_mem hv1 hv2
· exact fun hv => ⟨v +ᵥ p, vadd_mem_mk' _ hv, p, self_mem_mk' _ _, (vadd_vsub _ _).symm⟩
#align affine_subspace.direction_mk' AffineSubspace.direction_mk'
/-- A point lies in an affine subspace constructed from another point and a direction if and only
if their difference is in that direction. -/
theorem mem_mk'_iff_vsub_mem {p₁ p₂ : P} {direction : Submodule k V} :
p₂ ∈ mk' p₁ direction ↔ p₂ -ᵥ p₁ ∈ direction := by
refine' ⟨fun h => _, fun h => _⟩
· rw [← direction_mk' p₁ direction]
exact vsub_mem_direction h (self_mem_mk' _ _)
· rw [← vsub_vadd p₂ p₁]
exact vadd_mem_mk' p₁ h
#align affine_subspace.mem_mk'_iff_vsub_mem AffineSubspace.mem_mk'_iff_vsub_mem
/-- Constructing an affine subspace from a point in a subspace and that subspace's direction
yields the original subspace. -/
@[simp]
theorem mk'_eq {s : AffineSubspace k P} {p : P} (hp : p ∈ s) : mk' p s.direction = s :=
ext_of_direction_eq (direction_mk' p s.direction) ⟨p, Set.mem_inter (self_mem_mk' _ _) hp⟩
#align affine_subspace.mk'_eq AffineSubspace.mk'_eq
/-- If an affine subspace contains a set of points, it contains the `spanPoints` of that set. -/
theorem spanPoints_subset_coe_of_subset_coe {s : Set P} {s1 : AffineSubspace k P} (h : s ⊆ s1) :
spanPoints k s ⊆ s1 := by
rintro p ⟨p1, hp1, v, hv, hp⟩
rw [hp]
have hp1s1 : p1 ∈ (s1 : Set P) := Set.mem_of_mem_of_subset hp1 h
refine' vadd_mem_of_mem_direction _ hp1s1
have hs : vectorSpan k s ≤ s1.direction := vectorSpan_mono k h
rw [SetLike.le_def] at hs
rw [← SetLike.mem_coe]
exact Set.mem_of_mem_of_subset hv hs
#align affine_subspace.span_points_subset_coe_of_subset_coe AffineSubspace.spanPoints_subset_coe_of_subset_coe
end AffineSubspace
namespace Submodule
variable {k V : Type*} [Ring k] [AddCommGroup V] [Module k V]
@[simp]
theorem mem_toAffineSubspace {p : Submodule k V} {x : V} :
x ∈ p.toAffineSubspace ↔ x ∈ p :=
Iff.rfl
@[simp]
theorem toAffineSubspace_direction (s : Submodule k V) : s.toAffineSubspace.direction = s := by
ext x; simp [← s.toAffineSubspace.vadd_mem_iff_mem_direction _ s.zero_mem]
end Submodule
theorem AffineMap.lineMap_mem {k V P : Type*} [Ring k] [AddCommGroup V] [Module k V]
[AddTorsor V P] {Q : AffineSubspace k P} {p₀ p₁ : P} (c : k) (h₀ : p₀ ∈ Q) (h₁ : p₁ ∈ Q) :
AffineMap.lineMap p₀ p₁ c ∈ Q := by
rw [AffineMap.lineMap_apply]
exact Q.smul_vsub_vadd_mem c h₁ h₀ h₀
#align affine_map.line_map_mem AffineMap.lineMap_mem
section affineSpan
variable (k : Type*) {V : Type*} {P : Type*} [Ring k] [AddCommGroup V] [Module k V]
[AffineSpace V P]
/-- The affine span of a set of points is the smallest affine subspace containing those points.
(Actually defined here in terms of spans in modules.) -/
def affineSpan (s : Set P) : AffineSubspace k P where
carrier := spanPoints k s
smul_vsub_vadd_mem c _ _ _ hp1 hp2 hp3 :=
vadd_mem_spanPoints_of_mem_spanPoints_of_mem_vectorSpan k hp3
((vectorSpan k s).smul_mem c
(vsub_mem_vectorSpan_of_mem_spanPoints_of_mem_spanPoints k hp1 hp2))
#align affine_span affineSpan
/-- The affine span, converted to a set, is `spanPoints`. -/
@[simp]
theorem coe_affineSpan (s : Set P) : (affineSpan k s : Set P) = spanPoints k s :=
rfl
#align coe_affine_span coe_affineSpan
/-- A set is contained in its affine span. -/
theorem subset_affineSpan (s : Set P) : s ⊆ affineSpan k s :=
subset_spanPoints k s
#align subset_affine_span subset_affineSpan
/-- The direction of the affine span is the `vectorSpan`. -/
theorem direction_affineSpan (s : Set P) : (affineSpan k s).direction = vectorSpan k s := by
apply le_antisymm
· refine' Submodule.span_le.2 _
rintro v ⟨p1, ⟨p2, hp2, v1, hv1, hp1⟩, p3, ⟨p4, hp4, v2, hv2, hp3⟩, rfl⟩
simp only [SetLike.mem_coe]
rw [hp1, hp3, vsub_vadd_eq_vsub_sub, vadd_vsub_assoc]
exact
(vectorSpan k s).sub_mem ((vectorSpan k s).add_mem hv1 (vsub_mem_vectorSpan k hp2 hp4)) hv2
· exact vectorSpan_mono k (subset_spanPoints k s)
#align direction_affine_span direction_affineSpan
/-- A point in a set is in its affine span. -/
theorem mem_affineSpan {p : P} {s : Set P} (hp : p ∈ s) : p ∈ affineSpan k s :=
mem_spanPoints k p s hp
#align mem_affine_span mem_affineSpan
end affineSpan
namespace AffineSubspace
variable {k : Type*} {V : Type*} {P : Type*} [Ring k] [AddCommGroup V] [Module k V]
[S : AffineSpace V P]
instance : CompleteLattice (AffineSubspace k P) :=
{
PartialOrder.lift ((↑) : AffineSubspace k P → Set P)
coe_injective with
sup := fun s1 s2 => affineSpan k (s1 ∪ s2)
le_sup_left := fun s1 s2 =>
Set.Subset.trans (Set.subset_union_left (s1 : Set P) s2) (subset_spanPoints k _)
le_sup_right := fun s1 s2 =>
Set.Subset.trans (Set.subset_union_right (s1 : Set P) s2) (subset_spanPoints k _)
sup_le := fun s1 s2 s3 hs1 hs2 => spanPoints_subset_coe_of_subset_coe (Set.union_subset hs1 hs2)
inf := fun s1 s2 =>
mk (s1 ∩ s2) fun c p1 p2 p3 hp1 hp2 hp3 =>
⟨s1.smul_vsub_vadd_mem c hp1.1 hp2.1 hp3.1, s2.smul_vsub_vadd_mem c hp1.2 hp2.2 hp3.2⟩
inf_le_left := fun _ _ => Set.inter_subset_left _ _
inf_le_right := fun _ _ => Set.inter_subset_right _ _
le_sInf := fun S s1 hs1 => by
-- Porting note: surely there is an easier way?
refine' Set.subset_sInter (t := (s1 : Set P)) _
rintro t ⟨s, _hs, rfl⟩
exact Set.subset_iInter (hs1 s)
top :=
{ carrier := Set.univ
smul_vsub_vadd_mem := fun _ _ _ _ _ _ _ => Set.mem_univ _ }
le_top := fun _ _ _ => Set.mem_univ _
bot :=
{ carrier := ∅
smul_vsub_vadd_mem := fun _ _ _ _ => False.elim }
bot_le := fun _ _ => False.elim
sSup := fun s => affineSpan k (⋃ s' ∈ s, (s' : Set P))
sInf := fun s =>
mk (⋂ s' ∈ s, (s' : Set P)) fun c p1 p2 p3 hp1 hp2 hp3 =>
Set.mem_iInter₂.2 fun s2 hs2 => by
rw [Set.mem_iInter₂] at *
exact s2.smul_vsub_vadd_mem c (hp1 s2 hs2) (hp2 s2 hs2) (hp3 s2 hs2)
le_sSup := fun _ _ h => Set.Subset.trans (Set.subset_biUnion_of_mem h) (subset_spanPoints k _)
sSup_le := fun _ _ h => spanPoints_subset_coe_of_subset_coe (Set.iUnion₂_subset h)
sInf_le := fun _ _ => Set.biInter_subset_of_mem
le_inf := fun _ _ _ => Set.subset_inter }
instance : Inhabited (AffineSubspace k P) :=
⟨⊤⟩
/-- The `≤` order on subspaces is the same as that on the corresponding sets. -/
theorem le_def (s1 s2 : AffineSubspace k P) : s1 ≤ s2 ↔ (s1 : Set P) ⊆ s2 :=
Iff.rfl
#align affine_subspace.le_def AffineSubspace.le_def
/-- One subspace is less than or equal to another if and only if all its points are in the second
subspace. -/
theorem le_def' (s1 s2 : AffineSubspace k P) : s1 ≤ s2 ↔ ∀ p ∈ s1, p ∈ s2 :=
Iff.rfl
#align affine_subspace.le_def' AffineSubspace.le_def'
/-- The `<` order on subspaces is the same as that on the corresponding sets. -/
theorem lt_def (s1 s2 : AffineSubspace k P) : s1 < s2 ↔ (s1 : Set P) ⊂ s2 :=
Iff.rfl
#align affine_subspace.lt_def AffineSubspace.lt_def
/-- One subspace is not less than or equal to another if and only if it has a point not in the
second subspace. -/
theorem not_le_iff_exists (s1 s2 : AffineSubspace k P) : ¬s1 ≤ s2 ↔ ∃ p ∈ s1, p ∉ s2 :=
Set.not_subset
#align affine_subspace.not_le_iff_exists AffineSubspace.not_le_iff_exists
/-- If a subspace is less than another, there is a point only in the second. -/
theorem exists_of_lt {s1 s2 : AffineSubspace k P} (h : s1 < s2) : ∃ p ∈ s2, p ∉ s1 :=
Set.exists_of_ssubset h
#align affine_subspace.exists_of_lt AffineSubspace.exists_of_lt
/-- A subspace is less than another if and only if it is less than or equal to the second subspace
and there is a point only in the second. -/
theorem lt_iff_le_and_exists (s1 s2 : AffineSubspace k P) : s1 < s2 ↔ s1 ≤ s2 ∧ ∃ p ∈ s2, p ∉ s1 :=
by rw [lt_iff_le_not_le, not_le_iff_exists]
#align affine_subspace.lt_iff_le_and_exists AffineSubspace.lt_iff_le_and_exists
/-- If an affine subspace is nonempty and contained in another with the same direction, they are
equal. -/
theorem eq_of_direction_eq_of_nonempty_of_le {s₁ s₂ : AffineSubspace k P}
(hd : s₁.direction = s₂.direction) (hn : (s₁ : Set P).Nonempty) (hle : s₁ ≤ s₂) : s₁ = s₂ :=
let ⟨p, hp⟩ := hn
ext_of_direction_eq hd ⟨p, hp, hle hp⟩
#align affine_subspace.eq_of_direction_eq_of_nonempty_of_le AffineSubspace.eq_of_direction_eq_of_nonempty_of_le
variable (k V)
/-- The affine span is the `sInf` of subspaces containing the given points. -/
theorem affineSpan_eq_sInf (s : Set P) :
affineSpan k s = sInf { s' : AffineSubspace k P | s ⊆ s' } :=
le_antisymm (spanPoints_subset_coe_of_subset_coe <| Set.subset_iInter₂ fun _ => id)
(sInf_le (subset_spanPoints k _))
#align affine_subspace.affine_span_eq_Inf AffineSubspace.affineSpan_eq_sInf
variable (P)
/-- The Galois insertion formed by `affineSpan` and coercion back to a set. -/
protected def gi : GaloisInsertion (affineSpan k) ((↑) : AffineSubspace k P → Set P) where
choice s _ := affineSpan k s
gc s1 _s2 :=
⟨fun h => Set.Subset.trans (subset_spanPoints k s1) h, spanPoints_subset_coe_of_subset_coe⟩
le_l_u _ := subset_spanPoints k _
choice_eq _ _ := rfl
#align affine_subspace.gi AffineSubspace.gi
/-- The span of the empty set is `⊥`. -/
@[simp]
theorem span_empty : affineSpan k (∅ : Set P) = ⊥ :=
(AffineSubspace.gi k V P).gc.l_bot
#align affine_subspace.span_empty AffineSubspace.span_empty
/-- The span of `univ` is `⊤`. -/
@[simp]
theorem span_univ : affineSpan k (Set.univ : Set P) = ⊤ :=
eq_top_iff.2 <| subset_spanPoints k _
#align affine_subspace.span_univ AffineSubspace.span_univ
variable {k V P}
theorem _root_.affineSpan_le {s : Set P} {Q : AffineSubspace k P} :
affineSpan k s ≤ Q ↔ s ⊆ (Q : Set P) :=
(AffineSubspace.gi k V P).gc _ _
#align affine_span_le affineSpan_le
variable (k V) {p₁ p₂ : P}
/-- The affine span of a single point, coerced to a set, contains just that point. -/
@[simp 1001] -- Porting note: this needs to take priority over `coe_affineSpan`
theorem coe_affineSpan_singleton (p : P) : (affineSpan k ({p} : Set P) : Set P) = {p} := by
ext x
rw [mem_coe, ← vsub_right_mem_direction_iff_mem (mem_affineSpan k (Set.mem_singleton p)) _,
direction_affineSpan]
simp
#align affine_subspace.coe_affine_span_singleton AffineSubspace.coe_affineSpan_singleton
/-- A point is in the affine span of a single point if and only if they are equal. -/
@[simp]
theorem mem_affineSpan_singleton : p₁ ∈ affineSpan k ({p₂} : Set P) ↔ p₁ = p₂ := by
simp [← mem_coe]
#align affine_subspace.mem_affine_span_singleton AffineSubspace.mem_affineSpan_singleton
@[simp]
theorem preimage_coe_affineSpan_singleton (x : P) :
((↑) : affineSpan k ({x} : Set P) → P) ⁻¹' {x} = univ :=
eq_univ_of_forall fun y => (AffineSubspace.mem_affineSpan_singleton _ _).1 y.2
#align affine_subspace.preimage_coe_affine_span_singleton AffineSubspace.preimage_coe_affineSpan_singleton
/-- The span of a union of sets is the sup of their spans. -/
theorem span_union (s t : Set P) : affineSpan k (s ∪ t) = affineSpan k s ⊔ affineSpan k t :=
(AffineSubspace.gi k V P).gc.l_sup
#align affine_subspace.span_union AffineSubspace.span_union
/-- The span of a union of an indexed family of sets is the sup of their spans. -/
theorem span_iUnion {ι : Type*} (s : ι → Set P) :
affineSpan k (⋃ i, s i) = ⨆ i, affineSpan k (s i) :=
(AffineSubspace.gi k V P).gc.l_iSup
#align affine_subspace.span_Union AffineSubspace.span_iUnion
variable (P)
/-- `⊤`, coerced to a set, is the whole set of points. -/
@[simp]
theorem top_coe : ((⊤ : AffineSubspace k P) : Set P) = Set.univ :=
rfl
#align affine_subspace.top_coe AffineSubspace.top_coe
variable {P}
/-- All points are in `⊤`. -/
@[simp]
theorem mem_top (p : P) : p ∈ (⊤ : AffineSubspace k P) :=
Set.mem_univ p
#align affine_subspace.mem_top AffineSubspace.mem_top
variable (P)
/-- The direction of `⊤` is the whole module as a submodule. -/
@[simp]
theorem direction_top : (⊤ : AffineSubspace k P).direction = ⊤ := by
cases' S.nonempty with p
ext v
refine' ⟨imp_intro Submodule.mem_top, fun _hv => _⟩
have hpv : (v +ᵥ p -ᵥ p : V) ∈ (⊤ : AffineSubspace k P).direction :=
vsub_mem_direction (mem_top k V _) (mem_top k V _)
rwa [vadd_vsub] at hpv
#align affine_subspace.direction_top AffineSubspace.direction_top
/-- `⊥`, coerced to a set, is the empty set. -/
@[simp]
theorem bot_coe : ((⊥ : AffineSubspace k P) : Set P) = ∅ :=
rfl
#align affine_subspace.bot_coe AffineSubspace.bot_coe
theorem bot_ne_top : (⊥ : AffineSubspace k P) ≠ ⊤ := by
intro contra
rw [← ext_iff, bot_coe, top_coe] at contra
exact Set.empty_ne_univ contra
#align affine_subspace.bot_ne_top AffineSubspace.bot_ne_top
instance : Nontrivial (AffineSubspace k P) :=
⟨⟨⊥, ⊤, bot_ne_top k V P⟩⟩
theorem nonempty_of_affineSpan_eq_top {s : Set P} (h : affineSpan k s = ⊤) : s.Nonempty := by
rw [Set.nonempty_iff_ne_empty]
rintro rfl
rw [AffineSubspace.span_empty] at h
exact bot_ne_top k V P h
#align affine_subspace.nonempty_of_affine_span_eq_top AffineSubspace.nonempty_of_affineSpan_eq_top
/-- If the affine span of a set is `⊤`, then the vector span of the same set is the `⊤`. -/
theorem vectorSpan_eq_top_of_affineSpan_eq_top {s : Set P} (h : affineSpan k s = ⊤) :
vectorSpan k s = ⊤ := by rw [← direction_affineSpan, h, direction_top]
#align affine_subspace.vector_span_eq_top_of_affine_span_eq_top AffineSubspace.vectorSpan_eq_top_of_affineSpan_eq_top
/-- For a nonempty set, the affine span is `⊤` iff its vector span is `⊤`. -/
theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty {s : Set P} (hs : s.Nonempty) :
affineSpan k s = ⊤ ↔ vectorSpan k s = ⊤ := by
refine' ⟨vectorSpan_eq_top_of_affineSpan_eq_top k V P, _⟩
intro h
suffices Nonempty (affineSpan k s) by
obtain ⟨p, hp : p ∈ affineSpan k s⟩ := this
rw [eq_iff_direction_eq_of_mem hp (mem_top k V p), direction_affineSpan, h, direction_top]
obtain ⟨x, hx⟩ := hs
exact ⟨⟨x, mem_affineSpan k hx⟩⟩
#align affine_subspace.affine_span_eq_top_iff_vector_span_eq_top_of_nonempty AffineSubspace.affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty
/-- For a non-trivial space, the affine span of a set is `⊤` iff its vector span is `⊤`. -/
theorem affineSpan_eq_top_iff_vectorSpan_eq_top_of_nontrivial {s : Set P} [Nontrivial P] :
affineSpan k s = ⊤ ↔ vectorSpan k s = ⊤ := by
rcases s.eq_empty_or_nonempty with hs | hs
· simp [hs, subsingleton_iff_bot_eq_top, AddTorsor.subsingleton_iff V P, not_subsingleton]
· rw [affineSpan_eq_top_iff_vectorSpan_eq_top_of_nonempty k V P hs]
#align affine_subspace.affine_span_eq_top_iff_vector_span_eq_top_of_nontrivial AffineSubspace.affineSpan_eq_top_iff_vectorSpan_eq_top_of_nontrivial
theorem card_pos_of_affineSpan_eq_top {ι : Type*} [Fintype ι] {p : ι → P}
(h : affineSpan k (range p) = ⊤) : 0 < Fintype.card ι := by
obtain ⟨-, ⟨i, -⟩⟩ := nonempty_of_affineSpan_eq_top k V P h
exact Fintype.card_pos_iff.mpr ⟨i⟩
#align affine_subspace.card_pos_of_affine_span_eq_top AffineSubspace.card_pos_of_affineSpan_eq_top
attribute [local instance] toAddTorsor
/-- The top affine subspace is linearly equivalent to the affine space.
This is the affine version of `Submodule.topEquiv`. -/
@[simps! linear apply symm_apply_coe]
def topEquiv : (⊤ : AffineSubspace k P) ≃ᵃ[k] P where
toEquiv := Equiv.Set.univ P
linear := .ofEq _ _ (direction_top _ _ _) ≪≫ₗ Submodule.topEquiv
map_vadd' _p _v := rfl
variable {P}
/-- No points are in `⊥`. -/
theorem not_mem_bot (p : P) : p ∉ (⊥ : AffineSubspace k P) :=
Set.not_mem_empty p
#align affine_subspace.not_mem_bot AffineSubspace.not_mem_bot
variable (P)
/-- The direction of `⊥` is the submodule `⊥`. -/
@[simp]
theorem direction_bot : (⊥ : AffineSubspace k P).direction = ⊥ := by
rw [direction_eq_vectorSpan, bot_coe, vectorSpan_def, vsub_empty, Submodule.span_empty]
#align affine_subspace.direction_bot AffineSubspace.direction_bot
variable {k V P}
@[simp]
theorem coe_eq_bot_iff (Q : AffineSubspace k P) : (Q : Set P) = ∅ ↔ Q = ⊥ :=
coe_injective.eq_iff' (bot_coe _ _ _)
#align affine_subspace.coe_eq_bot_iff AffineSubspace.coe_eq_bot_iff
@[simp]
theorem coe_eq_univ_iff (Q : AffineSubspace k P) : (Q : Set P) = univ ↔ Q = ⊤ :=
coe_injective.eq_iff' (top_coe _ _ _)
#align affine_subspace.coe_eq_univ_iff AffineSubspace.coe_eq_univ_iff
theorem nonempty_iff_ne_bot (Q : AffineSubspace k P) : (Q : Set P).Nonempty ↔ Q ≠ ⊥ := by
rw [nonempty_iff_ne_empty]
exact not_congr Q.coe_eq_bot_iff
#align affine_subspace.nonempty_iff_ne_bot AffineSubspace.nonempty_iff_ne_bot
theorem eq_bot_or_nonempty (Q : AffineSubspace k P) : Q = ⊥ ∨ (Q : Set P).Nonempty := by
rw [nonempty_iff_ne_bot]
apply eq_or_ne
#align affine_subspace.eq_bot_or_nonempty AffineSubspace.eq_bot_or_nonempty
theorem subsingleton_of_subsingleton_span_eq_top {s : Set P} (h₁ : s.Subsingleton)
(h₂ : affineSpan k s = ⊤) : Subsingleton P := by
obtain ⟨p, hp⟩ := AffineSubspace.nonempty_of_affineSpan_eq_top k V P h₂
have : s = {p} := Subset.antisymm (fun q hq => h₁ hq hp) (by simp [hp])
rw [this, ← AffineSubspace.ext_iff, AffineSubspace.coe_affineSpan_singleton,
AffineSubspace.top_coe, eq_comm, ← subsingleton_iff_singleton (mem_univ _)] at h₂
exact subsingleton_of_univ_subsingleton h₂
#align affine_subspace.subsingleton_of_subsingleton_span_eq_top AffineSubspace.subsingleton_of_subsingleton_span_eq_top
theorem eq_univ_of_subsingleton_span_eq_top {s : Set P} (h₁ : s.Subsingleton)
(h₂ : affineSpan k s = ⊤) : s = (univ : Set P) := by
obtain ⟨p, hp⟩ := AffineSubspace.nonempty_of_affineSpan_eq_top k V P h₂
have : s = {p} := Subset.antisymm (fun q hq => h₁ hq hp) (by simp [hp])
rw [this, eq_comm, ← subsingleton_iff_singleton (mem_univ p), subsingleton_univ_iff]
exact subsingleton_of_subsingleton_span_eq_top h₁ h₂
#align affine_subspace.eq_univ_of_subsingleton_span_eq_top AffineSubspace.eq_univ_of_subsingleton_span_eq_top
/-- A nonempty affine subspace is `⊤` if and only if its direction is `⊤`. -/
@[simp]
theorem direction_eq_top_iff_of_nonempty {s : AffineSubspace k P} (h : (s : Set P).Nonempty) :
s.direction = ⊤ ↔ s = ⊤ := by
constructor
· intro hd
rw [← direction_top k V P] at hd
refine' ext_of_direction_eq hd _
simp [h]
· rintro rfl
simp
#align affine_subspace.direction_eq_top_iff_of_nonempty AffineSubspace.direction_eq_top_iff_of_nonempty
/-- The inf of two affine subspaces, coerced to a set, is the intersection of the two sets of
points. -/
@[simp]
theorem inf_coe (s1 s2 : AffineSubspace k P) : (s1 ⊓ s2 : Set P) = (s1 : Set P) ∩ s2 :=
rfl
#align affine_subspace.inf_coe AffineSubspace.inf_coe
/-- A point is in the inf of two affine subspaces if and only if it is in both of them. -/
theorem mem_inf_iff (p : P) (s1 s2 : AffineSubspace k P) : p ∈ s1 ⊓ s2 ↔ p ∈ s1 ∧ p ∈ s2 :=
Iff.rfl
#align affine_subspace.mem_inf_iff AffineSubspace.mem_inf_iff
/-- The direction of the inf of two affine subspaces is less than or equal to the inf of their
directions. -/
theorem direction_inf (s1 s2 : AffineSubspace k P) :
(s1 ⊓ s2).direction ≤ s1.direction ⊓ s2.direction := by
simp only [direction_eq_vectorSpan, vectorSpan_def]
exact
le_inf (sInf_le_sInf fun p hp => trans (vsub_self_mono (inter_subset_left _ _)) hp)
(sInf_le_sInf fun p hp => trans (vsub_self_mono (inter_subset_right _ _)) hp)
#align affine_subspace.direction_inf AffineSubspace.direction_inf
/-- If two affine subspaces have a point in common, the direction of their inf equals the inf of
their directions. -/
theorem direction_inf_of_mem {s₁ s₂ : AffineSubspace k P} {p : P} (h₁ : p ∈ s₁) (h₂ : p ∈ s₂) :
(s₁ ⊓ s₂).direction = s₁.direction ⊓ s₂.direction := by
ext v
rw [Submodule.mem_inf, ← vadd_mem_iff_mem_direction v h₁, ← vadd_mem_iff_mem_direction v h₂, ←
vadd_mem_iff_mem_direction v ((mem_inf_iff p s₁ s₂).2 ⟨h₁, h₂⟩), mem_inf_iff]
#align affine_subspace.direction_inf_of_mem AffineSubspace.direction_inf_of_mem
/-- If two affine subspaces have a point in their inf, the direction of their inf equals the inf of
their directions. -/
theorem direction_inf_of_mem_inf {s₁ s₂ : AffineSubspace k P} {p : P} (h : p ∈ s₁ ⊓ s₂) :
(s₁ ⊓ s₂).direction = s₁.direction ⊓ s₂.direction :=
direction_inf_of_mem ((mem_inf_iff p s₁ s₂).1 h).1 ((mem_inf_iff p s₁ s₂).1 h).2
#align affine_subspace.direction_inf_of_mem_inf AffineSubspace.direction_inf_of_mem_inf
/-- If one affine subspace is less than or equal to another, the same applies to their
directions. -/
theorem direction_le {s1 s2 : AffineSubspace k P} (h : s1 ≤ s2) : s1.direction ≤ s2.direction := by
simp only [direction_eq_vectorSpan, vectorSpan_def]
exact vectorSpan_mono k h
#align affine_subspace.direction_le AffineSubspace.direction_le
/-- If one nonempty affine subspace is less than another, the same applies to their directions -/
theorem direction_lt_of_nonempty {s1 s2 : AffineSubspace k P} (h : s1 < s2)
(hn : (s1 : Set P).Nonempty) : s1.direction < s2.direction := by
cases' hn with p hp
rw [lt_iff_le_and_exists] at h
rcases h with ⟨hle, p2, hp2, hp2s1⟩
rw [SetLike.lt_iff_le_and_exists]
use direction_le hle, p2 -ᵥ p, vsub_mem_direction hp2 (hle hp)
intro hm
rw [vsub_right_mem_direction_iff_mem hp p2] at hm
exact hp2s1 hm
#align affine_subspace.direction_lt_of_nonempty AffineSubspace.direction_lt_of_nonempty
/-- The sup of the directions of two affine subspaces is less than or equal to the direction of
their sup. -/
theorem sup_direction_le (s1 s2 : AffineSubspace k P) :
s1.direction ⊔ s2.direction ≤ (s1 ⊔ s2).direction := by
simp only [direction_eq_vectorSpan, vectorSpan_def]
exact
sup_le
(sInf_le_sInf fun p hp => Set.Subset.trans (vsub_self_mono (le_sup_left : s1 ≤ s1 ⊔ s2)) hp)
(sInf_le_sInf fun p hp => Set.Subset.trans (vsub_self_mono (le_sup_right : s2 ≤ s1 ⊔ s2)) hp)
#align affine_subspace.sup_direction_le AffineSubspace.sup_direction_le
/-- The sup of the directions of two nonempty affine subspaces with empty intersection is less than
the direction of their sup. -/
theorem sup_direction_lt_of_nonempty_of_inter_empty {s1 s2 : AffineSubspace k P}
(h1 : (s1 : Set P).Nonempty) (h2 : (s2 : Set P).Nonempty) (he : (s1 ∩ s2 : Set P) = ∅) :
s1.direction ⊔ s2.direction < (s1 ⊔ s2).direction := by
cases' h1 with p1 hp1
cases' h2 with p2 hp2
rw [SetLike.lt_iff_le_and_exists]
use sup_direction_le s1 s2, p2 -ᵥ p1,
vsub_mem_direction ((le_sup_right : s2 ≤ s1 ⊔ s2) hp2) ((le_sup_left : s1 ≤ s1 ⊔ s2) hp1)
intro h
rw [Submodule.mem_sup] at h
rcases h with ⟨v1, hv1, v2, hv2, hv1v2⟩
rw [← sub_eq_zero, sub_eq_add_neg, neg_vsub_eq_vsub_rev, add_comm v1, add_assoc, ←
vadd_vsub_assoc, ← neg_neg v2, add_comm, ← sub_eq_add_neg, ← vsub_vadd_eq_vsub_sub,
vsub_eq_zero_iff_eq] at hv1v2
refine' Set.Nonempty.ne_empty _ he
use v1 +ᵥ p1, vadd_mem_of_mem_direction hv1 hp1
rw [hv1v2]
exact vadd_mem_of_mem_direction (Submodule.neg_mem _ hv2) hp2
#align affine_subspace.sup_direction_lt_of_nonempty_of_inter_empty AffineSubspace.sup_direction_lt_of_nonempty_of_inter_empty
/-- If the directions of two nonempty affine subspaces span the whole module, they have nonempty
intersection. -/
theorem inter_nonempty_of_nonempty_of_sup_direction_eq_top {s1 s2 : AffineSubspace k P}
(h1 : (s1 : Set P).Nonempty) (h2 : (s2 : Set P).Nonempty)
(hd : s1.direction ⊔ s2.direction = ⊤) : ((s1 : Set P) ∩ s2).Nonempty := by
by_contra h
rw [Set.not_nonempty_iff_eq_empty] at h
have hlt := sup_direction_lt_of_nonempty_of_inter_empty h1 h2 h
rw [hd] at hlt
exact not_top_lt hlt
#align affine_subspace.inter_nonempty_of_nonempty_of_sup_direction_eq_top AffineSubspace.inter_nonempty_of_nonempty_of_sup_direction_eq_top