@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
4
4
Author: Joseph Myers.
5
5
-/
6
6
import algebra.add_torsor
7
+ import data.indicator_function
7
8
import linear_algebra.basis
8
9
9
10
noncomputable theory
@@ -59,6 +60,14 @@ def vector_span (s : set P) : submodule k V := submodule.span k (vsub_set V s)
59
60
lemma vector_span_def (s : set P) : vector_span k V s = submodule.span k (vsub_set V s) :=
60
61
rfl
61
62
63
+ variables (P)
64
+
65
+ /-- The `vector_span` of the empty set is `⊥`. -/
66
+ @[simp] lemma vector_span_empty : vector_span k V (∅ : set P) = ⊥ :=
67
+ by rw [vector_span_def, vsub_set_empty, submodule.span_empty]
68
+
69
+ variables {P}
70
+
62
71
/-- The `vsub_set` lies within the `vector_span`. -/
63
72
lemma vsub_set_subset_vector_span (s : set P) : vsub_set V s ⊆ vector_span k V s :=
64
73
submodule.subset_span
@@ -85,11 +94,18 @@ lemma mem_span_points (p : P) (s : set P) : p ∈ s → p ∈ span_points k V s
85
94
lemma subset_span_points (s : set P) : s ⊆ span_points k V s :=
86
95
λ p, mem_span_points k V p s
87
96
88
- /-- The set of points in the affine span of a nonempty set of points
89
- is nonempty. -/
90
- lemma span_points_nonempty_of_nonempty {s : set P} :
91
- s.nonempty → (span_points k V s).nonempty
92
- | ⟨p, hp⟩ := ⟨p, mem_span_points k V p s hp⟩
97
+ /-- The `span_points` of a set is nonempty if and only if that set
98
+ is. -/
99
+ @[simp] lemma span_points_nonempty (s : set P) :
100
+ (span_points k V s).nonempty ↔ s.nonempty :=
101
+ begin
102
+ split,
103
+ { contrapose,
104
+ rw [set.not_nonempty_iff_eq_empty, set.not_nonempty_iff_eq_empty],
105
+ intro h,
106
+ simp [h, span_points] },
107
+ { exact λ ⟨p, hp⟩, ⟨p, mem_span_points k V p s hp⟩ }
108
+ end
93
109
94
110
/-- Adding a point in the affine span and a vector in the spanning
95
111
submodule produces a point in the affine span. -/
@@ -199,6 +215,16 @@ begin
199
215
rw [vsub_self, smul_zero]
200
216
end
201
217
218
+ /-- The weighted sum is unaffected by changing the weights to the
219
+ corresponding indicator function and adding points to the set. -/
220
+ lemma weighted_vsub_of_point_indicator_subset (w : ι → k) (p : ι → P) (b : P) {s₁ s₂ : finset ι}
221
+ (h : s₁ ⊆ s₂) :
222
+ s₁.weighted_vsub_of_point V p b w = s₂.weighted_vsub_of_point V p b (set.indicator ↑s₁ w) :=
223
+ begin
224
+ rw [weighted_vsub_of_point_apply, weighted_vsub_of_point_apply],
225
+ exact set.sum_indicator_subset_of_eq_zero w (λ i wi, wi • (p i -ᵥ b : V)) h (λ i, zero_smul k _)
226
+ end
227
+
202
228
/-- A weighted sum of the results of subtracting a default base point
203
229
from the given points, as a linear map on the weights. This is
204
230
intended to be used when the sum of the weights is 0; that condition
@@ -222,6 +248,17 @@ lemma weighted_vsub_eq_weighted_vsub_of_point_of_sum_eq_zero (w : ι → k) (p :
222
248
(h : ∑ i in s, w i = 0 ) (b : P) : s.weighted_vsub V p w = s.weighted_vsub_of_point V p b w :=
223
249
s.weighted_vsub_of_point_eq_of_sum_eq_zero V w p h _ _
224
250
251
+ /-- The `weighted_vsub` for an empty set is 0. -/
252
+ @[simp] lemma weighted_vsub_empty (w : ι → k) (p : ι → P) :
253
+ (∅ : finset ι).weighted_vsub V p w = 0 :=
254
+ by simp [weighted_vsub_apply]
255
+
256
+ /-- The weighted sum is unaffected by changing the weights to the
257
+ corresponding indicator function and adding points to the set. -/
258
+ lemma weighted_vsub_indicator_subset (w : ι → k) (p : ι → P) {s₁ s₂ : finset ι} (h : s₁ ⊆ s₂) :
259
+ s₁.weighted_vsub V p w = s₂.weighted_vsub V p (set.indicator ↑s₁ w) :=
260
+ weighted_vsub_of_point_indicator_subset _ _ _ _ h
261
+
225
262
/-- A weighted sum of the results of subtracting a default base point
226
263
from the given points, added to that base point. This is intended to
227
264
be used when the sum of the weights is 1, in which case it is an
@@ -231,6 +268,18 @@ require it. -/
231
268
def affine_combination (w : ι → k) (p : ι → P) : P :=
232
269
s.weighted_vsub_of_point V p (classical.choice S.nonempty) w +ᵥ (classical.choice S.nonempty)
233
270
271
+ /-- Applying `affine_combination` with given weights. This is for the
272
+ case where a result involving a default base point is OK (for example,
273
+ when that base point will cancel out later); a more typical use case
274
+ for `affine_combination` would involve selecting a preferred base
275
+ point with
276
+ `affine_combination_eq_weighted_vsub_of_point_vadd_of_sum_eq_one` and
277
+ then using `weighted_vsub_of_point_apply`. -/
278
+ lemma affine_combination_apply (w : ι → k) (p : ι → P) :
279
+ s.affine_combination V w p =
280
+ s.weighted_vsub_of_point V p (classical.choice S.nonempty) w +ᵥ (classical.choice S.nonempty) :=
281
+ rfl
282
+
234
283
/-- `affine_combination` gives the sum with any base point, when the
235
284
sum of the weights is 1. -/
236
285
lemma affine_combination_eq_weighted_vsub_of_point_vadd_of_sum_eq_one (w : ι → k) (p : ι → P)
@@ -255,6 +304,31 @@ begin
255
304
exact (linear_map.map_sub _ _ _).symm
256
305
end
257
306
307
+ /-- An `affine_combination` equals a point if that point is in the set
308
+ and has weight 1 and the other points in the set have weight 0. -/
309
+ @[simp] lemma affine_combination_of_eq_one_of_eq_zero (w : ι → k) (p : ι → P) {i : ι}
310
+ (his : i ∈ s) (hwi : w i = 1 ) (hw0 : ∀ i2 ∈ s, i2 ≠ i → w i2 = 0 ) :
311
+ s.affine_combination V w p = p i :=
312
+ begin
313
+ have h1 : ∑ i in s, w i = 1 := hwi ▸ finset.sum_eq_single i hw0 (λ h, false.elim (h his)),
314
+ rw [s.affine_combination_eq_weighted_vsub_of_point_vadd_of_sum_eq_one V w p h1 (p i),
315
+ weighted_vsub_of_point_apply],
316
+ convert zero_vadd V (p i),
317
+ convert finset.sum_eq_zero _,
318
+ intros i2 hi2,
319
+ by_cases h : i2 = i,
320
+ { simp [h] },
321
+ { simp [hw0 i2 hi2 h] }
322
+ end
323
+
324
+ /-- An affine combination is unaffected by changing the weights to the
325
+ corresponding indicator function and adding points to the set. -/
326
+ lemma affine_combination_indicator_subset (w : ι → k) (p : ι → P) {s₁ s₂ : finset ι}
327
+ (h : s₁ ⊆ s₂) :
328
+ s₁.affine_combination V w p = s₂.affine_combination V (set.indicator ↑s₁ w) p :=
329
+ by rw [affine_combination_apply, affine_combination_apply,
330
+ weighted_vsub_of_point_indicator_subset _ _ _ _ h]
331
+
258
332
end finset
259
333
260
334
section affine_independent
@@ -895,6 +969,217 @@ end
895
969
896
970
end affine_subspace
897
971
972
+ namespace affine_space
973
+
974
+ variables (k : Type *) (V : Type *) {P : Type *} [ring k] [add_comm_group V] [module k V]
975
+ [affine_space k V P]
976
+ variables {ι : Type *}
977
+
978
+ /-- The `vector_span` is the span of the pairwise subtractions with a
979
+ given point on the left. -/
980
+ lemma vector_span_eq_span_vsub_set_left {s : set P} {p : P} (hp : p ∈ s) :
981
+ vector_span k V s = submodule.span k {v | ∃ p2 ∈ s, v = p -ᵥ p2} :=
982
+ begin
983
+ rw vector_span_def,
984
+ refine le_antisymm _ (submodule.span_mono _),
985
+ { rw submodule.span_le,
986
+ rintros v ⟨p1, hp1, p2, hp2, hv⟩,
987
+ rw ←vsub_sub_vsub_cancel_left V p1 p2 p at hv,
988
+ rw [hv, submodule.mem_coe, submodule.mem_span],
989
+ exact λ m hm, submodule.sub_mem _ (hm ⟨p2, hp2, rfl⟩) (hm ⟨p1, hp1, rfl⟩) },
990
+ { rintros v ⟨p2, hp2, hv⟩,
991
+ exact ⟨p, hp, p2, hp2, hv⟩ }
992
+ end
993
+
994
+ /-- The `vector_span` is the span of the pairwise subtractions with a
995
+ given point on the right. -/
996
+ lemma vector_span_eq_span_vsub_set_right {s : set P} {p : P} (hp : p ∈ s) :
997
+ vector_span k V s = submodule.span k {v | ∃ p2 ∈ s, v = p2 -ᵥ p} :=
998
+ begin
999
+ rw vector_span_def,
1000
+ refine le_antisymm _ (submodule.span_mono _),
1001
+ { rw submodule.span_le,
1002
+ rintros v ⟨p1, hp1, p2, hp2, hv⟩,
1003
+ rw ←vsub_sub_vsub_cancel_right V p1 p2 p at hv,
1004
+ rw [hv, submodule.mem_coe, submodule.mem_span],
1005
+ exact λ m hm, submodule.sub_mem _ (hm ⟨p1, hp1, rfl⟩) (hm ⟨p2, hp2, rfl⟩) },
1006
+ { rintros v ⟨p2, hp2, hv⟩,
1007
+ exact ⟨p2, hp2, p, hp, hv⟩ }
1008
+ end
1009
+
1010
+ /-- The `vector_span` of an indexed family is the span of the pairwise
1011
+ subtractions with a given point on the left. -/
1012
+ lemma vector_span_range_eq_span_range_vsub_left (p : ι → P) (i0 : ι) :
1013
+ vector_span k V (set.range p) = submodule.span k (set.range (λ (i : ι), p i0 -ᵥ p i)) :=
1014
+ begin
1015
+ simp_rw [vector_span_eq_span_vsub_set_left k V (set.mem_range_self i0), set.exists_range_iff],
1016
+ conv_lhs { congr, congr, funext, conv { congr, funext, rw eq_comm } },
1017
+ refl
1018
+ end
1019
+
1020
+ /-- The `vector_span` of an indexed family is the span of the pairwise
1021
+ subtractions with a given point on the right. -/
1022
+ lemma vector_span_range_eq_span_range_vsub_right (p : ι → P) (i0 : ι) :
1023
+ vector_span k V (set.range p) = submodule.span k (set.range (λ (i : ι), p i -ᵥ p i0)) :=
1024
+ begin
1025
+ simp_rw [vector_span_eq_span_vsub_set_right k V (set.mem_range_self i0), set.exists_range_iff],
1026
+ conv_lhs { congr, congr, funext, conv { congr, funext, rw eq_comm } },
1027
+ refl
1028
+ end
1029
+
1030
+ /-- The affine span of a set is nonempty if and only if that set
1031
+ is. -/
1032
+ lemma affine_span_nonempty (s : set P) :
1033
+ (affine_span k V s : set P).nonempty ↔ s.nonempty :=
1034
+ span_points_nonempty k V s
1035
+
1036
+ variables {k}
1037
+
1038
+ /-- A `weighted_vsub` with sum of weights 0 is in the `vector_span` of
1039
+ an indexed family. -/
1040
+ lemma weighted_vsub_mem_vector_span {s : finset ι} {w : ι → k}
1041
+ (h : ∑ i in s, w i = 0 ) (p : ι → P) :
1042
+ s.weighted_vsub V p w ∈ vector_span k V (set.range p) :=
1043
+ begin
1044
+ by_cases hn : nonempty ι,
1045
+ { cases hn with i0,
1046
+ rw [vector_span_range_eq_span_range_vsub_right k V p i0, ←set.image_univ,
1047
+ finsupp.mem_span_iff_total,
1048
+ finset.weighted_vsub_eq_weighted_vsub_of_point_of_sum_eq_zero V s w p h (p i0),
1049
+ finset.weighted_vsub_of_point_apply],
1050
+ let w' := set.indicator ↑s w,
1051
+ have hwx : ∀ i, w' i ≠ 0 → i ∈ s := λ i, set.mem_of_indicator_ne_zero,
1052
+ use [finsupp.on_finset s w' hwx, set.subset_univ _],
1053
+ rw [finsupp.total_apply, finsupp.on_finset_sum hwx],
1054
+ { apply finset.sum_congr rfl,
1055
+ intros i hi,
1056
+ simp [w', set.indicator_apply, if_pos hi] },
1057
+ { exact λ _, zero_smul k _ } },
1058
+ { simp [finset.eq_empty_of_not_nonempty hn s] }
1059
+ end
1060
+
1061
+ /-- An `affine_combination` with sum of weights 1 is in the
1062
+ `affine_span` of an indexed family, if the underlying ring is
1063
+ nontrivial. -/
1064
+ lemma affine_combination_mem_affine_span [nontrivial k] {s : finset ι} {w : ι → k}
1065
+ (h : ∑ i in s, w i = 1 ) (p : ι → P) :
1066
+ s.affine_combination V w p ∈ affine_span k V (set.range p) :=
1067
+ begin
1068
+ have hnz : ∑ i in s, w i ≠ 0 := h.symm ▸ one_ne_zero,
1069
+ have hn : s.nonempty := finset.nonempty_of_sum_ne_zero hnz,
1070
+ cases hn with i1 hi1,
1071
+ let w1 : ι → k := function.update (function.const ι 0 ) i1 1 ,
1072
+ have hw1 : ∑ i in s, w1 i = 1 ,
1073
+ { rw [finset.sum_update_of_mem hi1, finset.sum_const_zero, add_zero] },
1074
+ have hw1s : s.affine_combination V w1 p = p i1 :=
1075
+ s.affine_combination_of_eq_one_of_eq_zero V w1 p hi1 (function.update_same _ _ _)
1076
+ (λ _ _ hne, function.update_noteq hne _ _),
1077
+ have hv : s.affine_combination V w p -ᵥ p i1 ∈ (affine_span k V (set.range p)).direction,
1078
+ { rw [direction_affine_span, ←hw1s, finset.affine_combination_vsub],
1079
+ apply weighted_vsub_mem_vector_span,
1080
+ simp [pi.sub_apply, h, hw1] },
1081
+ rw ←vsub_vadd V (s.affine_combination V w p) (p i1),
1082
+ exact affine_subspace.vadd_mem_of_mem_direction hv (mem_affine_span k V (set.mem_range_self _))
1083
+ end
1084
+
1085
+ variables (k) {V}
1086
+
1087
+ /-- A vector is in the `vector_span` of an indexed family if and only
1088
+ if it is a `weighted_vsub` with sum of weights 0. -/
1089
+ lemma mem_vector_span_iff_eq_weighted_vsub {v : V} {p : ι → P} :
1090
+ v ∈ vector_span k V (set.range p) ↔
1091
+ ∃ (s : finset ι) (w : ι → k) (h : ∑ i in s, w i = 0 ), v = s.weighted_vsub V p w :=
1092
+ begin
1093
+ split,
1094
+ { by_cases hn : nonempty ι,
1095
+ { cases hn with i0,
1096
+ rw [vector_span_range_eq_span_range_vsub_right k V p i0, ←set.image_univ,
1097
+ finsupp.mem_span_iff_total],
1098
+ rintros ⟨l, hl, hv⟩,
1099
+ use insert i0 l.support,
1100
+ set w := (l : ι → k) -
1101
+ function.update (function.const ι 0 : ι → k) i0 (∑ i in l.support, l i) with hwdef,
1102
+ use w,
1103
+ have hw : ∑ i in insert i0 l.support, w i = 0 ,
1104
+ { rw hwdef,
1105
+ simp_rw [pi.sub_apply, finset.sum_sub_distrib,
1106
+ finset.sum_update_of_mem (finset.mem_insert_self _ _), finset.sum_const_zero,
1107
+ finset.sum_insert_of_eq_zero_if_not_mem finsupp.not_mem_support_iff.1 ,
1108
+ add_zero, sub_self] },
1109
+ use hw,
1110
+ have hz : w i0 • (p i0 -ᵥ p i0 : V) = 0 := (vsub_self V (p i0)).symm ▸ smul_zero _,
1111
+ change (λ i, w i • (p i -ᵥ p i0 : V)) i0 = 0 at hz,
1112
+ rw [finset.weighted_vsub_eq_weighted_vsub_of_point_of_sum_eq_zero V _ w p hw (p i0),
1113
+ finset.weighted_vsub_of_point_apply, ←hv, finsupp.total_apply,
1114
+ finset.sum_insert_zero hz],
1115
+ change ∑ i in l.support, l i • _ = _,
1116
+ congr,
1117
+ ext i,
1118
+ by_cases h : i = i0,
1119
+ { simp [h] },
1120
+ { simp [hwdef, h] } },
1121
+ { rw [set.range_eq_empty.2 hn, vector_span_empty, submodule.mem_bot],
1122
+ intro hv,
1123
+ use [∅],
1124
+ simp [hv] } },
1125
+ { rintros ⟨s, w, hw, rfl⟩,
1126
+ exact weighted_vsub_mem_vector_span V hw p }
1127
+ end
1128
+
1129
+ variables {k}
1130
+
1131
+ /-- A point in the `affine_span` of an indexed family is an
1132
+ `affine_combination` with sum of weights 1. -/
1133
+ lemma eq_affine_combination_of_mem_affine_span {p1 : P} {p : ι → P}
1134
+ (h : p1 ∈ affine_span k V (set.range p)) :
1135
+ ∃ (s : finset ι) (w : ι → k) (hw : ∑ i in s, w i = 1 ), p1 = s.affine_combination V w p :=
1136
+ begin
1137
+ have hn : ((affine_span k V (set.range p)) : set P).nonempty := ⟨p1, h⟩,
1138
+ rw [affine_span_nonempty, set.range_nonempty_iff_nonempty] at hn,
1139
+ cases hn with i0,
1140
+ have h0 : p i0 ∈ affine_span k V (set.range p) := mem_affine_span k V (set.mem_range_self i0),
1141
+ have hd : p1 -ᵥ p i0 ∈ (affine_span k V (set.range p)).direction :=
1142
+ affine_subspace.vsub_mem_direction h h0,
1143
+ rw [direction_affine_span, mem_vector_span_iff_eq_weighted_vsub] at hd,
1144
+ rcases hd with ⟨s, w, h, hs⟩,
1145
+ let s' := insert i0 s,
1146
+ let w' := set.indicator ↑s w,
1147
+ have h' : ∑ i in s', w' i = 0 ,
1148
+ { rw [←h, set.sum_indicator_subset _ (finset.subset_insert i0 s)] },
1149
+ have hs' : s'.weighted_vsub V p w' = p1 -ᵥ p i0,
1150
+ { rw hs,
1151
+ exact (finset.weighted_vsub_indicator_subset _ _ _ (finset.subset_insert i0 s)).symm },
1152
+ let w0 : ι → k := function.update (function.const ι 0 ) i0 1 ,
1153
+ have hw0 : ∑ i in s', w0 i = 1 ,
1154
+ { rw [finset.sum_update_of_mem (finset.mem_insert_self _ _), finset.sum_const_zero, add_zero] },
1155
+ have hw0s : s'.affine_combination V w0 p = p i0 :=
1156
+ s'.affine_combination_of_eq_one_of_eq_zero V w0 p
1157
+ (finset.mem_insert_self _ _)
1158
+ (function.update_same _ _ _)
1159
+ (λ _ _ hne, function.update_noteq hne _ _),
1160
+ use [s', w0 + w'],
1161
+ split,
1162
+ { simp [pi.add_apply, finset.sum_add_distrib, hw0, h'] },
1163
+ { rw [add_comm, ←finset.weighted_vsub_vadd_affine_combination, hw0s, hs', vsub_vadd] }
1164
+ end
1165
+
1166
+ variables (k V)
1167
+
1168
+ /-- A point is in the `affine_span` of an indexed family if and only
1169
+ if it is an `affine_combination` with sum of weights 1, provided the
1170
+ underlying ring is nontrivial. -/
1171
+ lemma mem_affine_span_iff_eq_affine_combination [nontrivial k] {p1 : P} {p : ι → P} :
1172
+ p1 ∈ affine_span k V (set.range p) ↔
1173
+ ∃ (s : finset ι) (w : ι → k) (hw : ∑ i in s, w i = 1 ), p1 = s.affine_combination V w p :=
1174
+ begin
1175
+ split,
1176
+ { exact eq_affine_combination_of_mem_affine_span },
1177
+ { rintros ⟨s, w, hw, rfl⟩,
1178
+ exact affine_combination_mem_affine_span V hw p }
1179
+ end
1180
+
1181
+ end affine_space
1182
+
898
1183
/-- An `affine_map k V1 P1 V2 P2` is a map from `P1` to `P2` that
899
1184
induces a corresponding linear map from `V1` to `V2`. -/
900
1185
structure affine_map (k : Type *) (V1 : Type *) (P1 : Type *) (V2 : Type *) (P2 : Type *)
0 commit comments