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

Commit 9172cdf

Browse files
committed
feat(linear_algebra/affine_space): affine spaces (#2816)
Define (very minimally) affine spaces (as an abbreviation for add_torsor in the case where the group is a vector space), affine subspaces, the affine span of a set of points and affine maps.
1 parent 6beebb0 commit 9172cdf

File tree

1 file changed

+267
-0
lines changed

1 file changed

+267
-0
lines changed
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
/-
2+
Copyright (c) 2020 Joseph Myers. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Joseph Myers.
5+
-/
6+
import algebra.add_torsor
7+
import linear_algebra.basis
8+
9+
noncomputable theory
10+
11+
/-!
12+
# Affine spaces
13+
14+
This file defines affine spaces (over modules) and subspaces, affine
15+
maps, and the affine span of a set of points.
16+
17+
## Implementation notes
18+
19+
This file is very minimal and many things are surely omitted. Most
20+
results can be deduced from corresponding results for modules or
21+
vector spaces. The variables `k` and `V` are explicit rather than
22+
implicit arguments to lemmas because otherwise the elaborator
23+
sometimes has problems inferring appropriate types and type class
24+
instances. Definitions of affine spaces vary as to whether a space
25+
with no points is permitted; here, we require a nonempty type of
26+
points (via the definition of torsors requiring a nonempty type).
27+
28+
## References
29+
30+
* https://en.wikipedia.org/wiki/Affine_space
31+
* https://en.wikipedia.org/wiki/Principal_homogeneous_space
32+
33+
-/
34+
35+
/-- `affine_space` is an abbreviation for `add_torsor` in the case
36+
where the group is a vector space, or more generally a module, but we
37+
omit the type classes `[ring k]` and `[module k V]` in the type
38+
synonym itself to simplify type class search.. -/
39+
@[nolint unused_arguments]
40+
abbreviation affine_space (k : Type*) (V : Type*) (P : Type*) [add_comm_group V] :=
41+
add_torsor V P
42+
43+
namespace affine_space
44+
45+
open add_action
46+
open add_torsor
47+
48+
variables (k : Type*) (V : Type*) {P : Type*} [ring k] [add_comm_group V] [module k V]
49+
variables [S : affine_space k V P]
50+
include S
51+
52+
/-- The submodule spanning the differences of a (possibly empty) set
53+
of points. -/
54+
def vector_span (s : set P) : submodule k V := submodule.span k (vsub_set V s)
55+
56+
/-- The points in the affine span of a (possibly empty) set of
57+
points. Use `affine_span` instead to get an `affine_subspace k V P`,
58+
if the set of points is known to be nonempty. -/
59+
def span_points (s : set P) : set P :=
60+
{p | ∃ p1 ∈ s, ∃ v ∈ (vector_span k V s), p = v +ᵥ p1}
61+
62+
/-- A point in a set is in its affine span. -/
63+
lemma mem_span_points (p : P) (s : set P) : p ∈ s → p ∈ span_points k V s
64+
| hp := ⟨p, hp, 0, submodule.zero _, (zero_vadd V p).symm⟩
65+
66+
/-- The set of points in the affine span of a nonempty set of points
67+
is nonempty. -/
68+
lemma span_points_nonempty_of_nonempty {s : set P} :
69+
s.nonempty → (span_points k V s).nonempty
70+
| ⟨p, hp⟩ := ⟨p, mem_span_points k V p s hp⟩
71+
72+
/-- Adding a point in the affine span and a vector in the spanning
73+
submodule produces a point in the affine span. -/
74+
lemma vadd_mem_span_points_of_mem_span_points_of_mem_vector_span {s : set P} {p : P} {v : V}
75+
(hp : p ∈ span_points k V s) (hv : v ∈ vector_span k V s) : v +ᵥ p ∈ span_points k V s :=
76+
begin
77+
rcases hp with ⟨p2, ⟨hp2, ⟨v2, ⟨hv2, hv2p⟩⟩⟩⟩,
78+
rw [hv2p, vadd_assoc],
79+
use [p2, hp2, v + v2, (vector_span k V s).add hv hv2, rfl]
80+
end
81+
82+
/-- Subtracting two points in the affine span produces a vector in the
83+
spanning submodule. -/
84+
lemma vsub_mem_vector_span_of_mem_span_points_of_mem_span_points {s : set P} {p1 p2 : P}
85+
(hp1 : p1 ∈ span_points k V s) (hp2 : p2 ∈ span_points k V s) :
86+
p1 -ᵥ p2 ∈ vector_span k V s :=
87+
begin
88+
rcases hp1 with ⟨p1a, ⟨hp1a, ⟨v1, ⟨hv1, hv1p⟩⟩⟩⟩,
89+
rcases hp2 with ⟨p2a, ⟨hp2a, ⟨v2, ⟨hv2, hv2p⟩⟩⟩⟩,
90+
rw [hv1p, hv2p, vsub_vadd_eq_vsub_sub V (v1 +ᵥ p1a), vadd_vsub_assoc, add_comm, add_sub_assoc],
91+
have hv1v2 : v1 - v2 ∈ vector_span k V s,
92+
{ apply (vector_span k V s).add hv1,
93+
rw ←neg_one_smul k v2,
94+
exact (vector_span k V s).smul (-1 : k) hv2 },
95+
refine (vector_span k V s).add _ hv1v2,
96+
unfold vector_span,
97+
change p1a -ᵥ p2a ∈ submodule.span k (vsub_set V s),
98+
have hp1p2 : p1a -ᵥ p2a ∈ vsub_set V s, { use [p1a, hp1a, p2a, hp2a] },
99+
have hp1p2s : vsub_set V s ⊆ submodule.span k (vsub_set V s) := submodule.subset_span,
100+
apply set.mem_of_mem_of_subset hp1p2 hp1p2s
101+
end
102+
103+
end affine_space
104+
105+
open add_torsor affine_space
106+
107+
/-- An `affine_subspace k V P` is a subset of an `affine_space k V P`
108+
that has an affine space structure induced by a corresponding subspace
109+
of the `module k V`. -/
110+
structure affine_subspace (k : Type*) (V : Type*) (P : Type*) [ring k] [add_comm_group V]
111+
[module k V] [affine_space k V P] :=
112+
(carrier : set P)
113+
(direction : submodule k V)
114+
(nonempty : carrier.nonempty)
115+
(add : ∀ (p : P) (v : V), p ∈ carrier → v ∈ direction → v +ᵥ p ∈ carrier)
116+
(sub : ∀ (p1 p2 : P), p1 ∈ carrier → p2 ∈ carrier → p1 -ᵥ p2 ∈ direction)
117+
118+
namespace affine_subspace
119+
120+
variables (k : Type*) (V : Type*) (P : Type*) [ring k] [add_comm_group V] [module k V]
121+
[S : affine_space k V P]
122+
include S
123+
124+
instance : has_coe (affine_subspace k V P) (set P) := ⟨carrier⟩
125+
instance : has_mem P (affine_subspace k V P) := ⟨λ p s, p ∈ (s : set P)⟩
126+
127+
/-- A point is in an affine subspace coerced to a set if and only if
128+
it is in that affine subspace. -/
129+
@[simp] lemma mem_coe (p : P) (s : affine_subspace k V P) :
130+
p ∈ (s : set P) ↔ p ∈ s :=
131+
iff.rfl
132+
133+
/-- The whole affine space as a subspace of itself. -/
134+
def univ : affine_subspace k V P :=
135+
{ carrier := set.univ,
136+
direction := submodule.span k set.univ,
137+
nonempty := set.nonempty_iff_univ_nonempty.1 S.nonempty,
138+
add := λ p v hp hv, set.mem_univ _,
139+
sub := begin
140+
intros p1 p2 hp1 hp2,
141+
apply set.mem_bInter,
142+
intros x hx,
143+
rw set.mem_set_of_eq at hx,
144+
exact set.mem_of_mem_of_subset (set.mem_univ _) hx
145+
end }
146+
147+
/-- `univ`, coerced to a set, is the whole set of points. -/
148+
@[simp] lemma univ_coe : (univ k V P : set P) = set.univ :=
149+
rfl
150+
151+
/-- All points are in `univ`. -/
152+
lemma mem_univ (p : P) : p ∈ univ k V P :=
153+
set.mem_univ p
154+
155+
instance : inhabited (affine_subspace k V P) := ⟨univ k V P⟩
156+
157+
end affine_subspace
158+
159+
section affine_span
160+
161+
variables (k : Type*) (V : Type*) (P : Type*) [ring k] [add_comm_group V] [module k V]
162+
[affine_space k V P]
163+
164+
/-- The affine span of a nonempty set of points is the smallest affine
165+
subspace containing those points. (Actually defined here in terms of
166+
spans in modules.) -/
167+
def affine_span (s : set P) (h : s.nonempty) : affine_subspace k V P :=
168+
{ carrier := span_points k V s,
169+
direction := vector_span k V s,
170+
nonempty := span_points_nonempty_of_nonempty k V h,
171+
add := λ p v hp hv, vadd_mem_span_points_of_mem_span_points_of_mem_vector_span k V hp hv,
172+
sub := λ p1 p2 hp1 hp2, vsub_mem_vector_span_of_mem_span_points_of_mem_span_points k V hp1 hp2 }
173+
174+
/-- The affine span, converted to a set, is `span_points`. -/
175+
@[simp] lemma affine_span_coe (s : set P) (h : s.nonempty) :
176+
(affine_span k V P s h : set P) = span_points k V s :=
177+
rfl
178+
179+
/-- A point in a set is in its affine span. -/
180+
lemma affine_span_mem (p : P) (s : set P) (hp : p ∈ s) : p ∈ affine_span k V P s ⟨p, hp⟩ :=
181+
mem_span_points k V p s hp
182+
183+
end affine_span
184+
185+
/-- An `affine_map k V1 P1 V2 P2` is a map from `P1` to `P2` that
186+
induces a corresponding linear map from `V1` to `V2`. -/
187+
structure affine_map (k : Type*) (V1 : Type*) (P1 : Type*) (V2 : Type*) (P2 : Type*)
188+
[ring k]
189+
[add_comm_group V1] [module k V1] [affine_space k V1 P1]
190+
[add_comm_group V2] [module k V2] [affine_space k V2 P2] :=
191+
(to_fun : P1 → P2)
192+
(linear : linear_map k V1 V2)
193+
(add : ∀ (p : P1) (v : V1), to_fun (v +ᵥ p) = linear.to_fun v +ᵥ to_fun p)
194+
195+
namespace affine_map
196+
197+
variables (k : Type*) (V1 : Type*) (P1 : Type*) (V2 : Type*) (P2 : Type*)
198+
(V3 : Type*) (P3 : Type*) [ring k]
199+
[add_comm_group V1] [module k V1] [S1 : affine_space k V1 P1]
200+
[add_comm_group V2] [module k V2] [affine_space k V2 P2]
201+
[add_comm_group V3] [module k V3] [affine_space k V3 P3]
202+
include S1
203+
204+
instance: has_coe_to_fun (affine_map k V1 P1 V2 P2) := ⟨_, to_fun⟩
205+
206+
/-- Constructing an affine map and coercing back to a function
207+
produces the same map. -/
208+
@[simp] lemma coe_mk (f : P1 → P2) (linear add) :
209+
((mk f linear add : affine_map k V1 P1 V2 P2) : P1 → P2) = f := rfl
210+
211+
/-- `to_fun` is the same as the result of coercing to a function. -/
212+
@[simp] lemma to_fun_eq_coe (f : affine_map k V1 P1 V2 P2) : f.to_fun = ⇑f := rfl
213+
214+
/-- An affine map on the result of adding a vector to a point produces
215+
the same result as the linear map applied to that vector, added to the
216+
affine map applied to that point. -/
217+
@[simp] lemma map_vadd (f : affine_map k V1 P1 V2 P2) (p : P1) (v : V1) :
218+
f (v +ᵥ p) = f.linear v +ᵥ f p := f.add p v
219+
220+
/-- The linear map on the result of subtracting two points is the
221+
result of subtracting the result of the affine map on those two
222+
points. -/
223+
lemma map_vsub (f : affine_map k V1 P1 V2 P2) (p1 p2 : P1) :
224+
f p1 -ᵥ f p2 = f.linear (p1 -ᵥ p2) :=
225+
by conv_lhs { rw [←vsub_vadd V1 p1 p2, map_vadd, vadd_vsub] }
226+
227+
/-- Two affine maps are equal if they coerce to the same function. -/
228+
@[ext] lemma ext (f g : affine_map k V1 P1 V2 P2) (h : (f : P1 → P2) = g) : f = g :=
229+
begin
230+
cases f,
231+
cases g,
232+
congr',
233+
ext v,
234+
change f_to_fun = g_to_fun at h,
235+
cases S1.nonempty with p,
236+
have hvp : f_to_fun (v +ᵥ p) = g_to_fun (v +ᵥ p), { rw h },
237+
rw [f_add, g_add, h] at hvp,
238+
exact vadd_right_cancel V2 _ hvp
239+
end
240+
241+
/-- Identity map as an affine map. -/
242+
def id : affine_map k V1 P1 V1 P1 :=
243+
{ to_fun := id,
244+
linear := linear_map.id,
245+
add := λ p v, rfl }
246+
247+
/-- The identity affine map acts as the identity. -/
248+
@[simp] lemma id_apply (p : P1) : (id k V1 P1) p = p := rfl
249+
250+
instance : inhabited (affine_map k V1 P1 V1 P1) := ⟨id k V1 P1⟩
251+
252+
/-- Composition of affine maps. -/
253+
def comp (f : affine_map k V2 P2 V3 P3) (g : affine_map k V1 P1 V2 P2) :
254+
affine_map k V1 P1 V3 P3 :=
255+
{ to_fun := f.to_fun ∘ g.to_fun,
256+
linear := f.linear.comp g.linear,
257+
add := begin
258+
intros p v,
259+
rw [function.comp_app, g.add, f.add],
260+
refl
261+
end }
262+
263+
/-- Composition of affine maps acts as applying the two functions. -/
264+
@[simp] lemma comp_apply (f : affine_map k V2 P2 V3 P3) (g : affine_map k V1 P1 V2 P2) (p : P1) :
265+
f.comp k V1 P1 V2 P2 V3 P3 g p = f (g p) := rfl
266+
267+
end affine_map

0 commit comments

Comments
 (0)