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

Commit 37f43bf

Browse files
committed
feat(linear_algebra/affine_space/barycentric_coords): define barycentric coordinates (#9472)
1 parent 06b184f commit 37f43bf

File tree

3 files changed

+132
-5
lines changed

3 files changed

+132
-5
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/-
2+
Copyright (c) 2021 Oliver Nash. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Oliver Nash
5+
-/
6+
import linear_algebra.affine_space.independent
7+
8+
/-!
9+
# Barycentric coordinates
10+
11+
Suppose `P` is an affine space modelled on the module `V` over the ring `k`, and `p : ι → P` is an
12+
affine-independent family of points spanning `P`. Given this data, each point `q : P` may be written
13+
uniquely as an affine combination: `q = w₀ p₀ + w₁ p₁ + ⋯` for some (finitely-supported) weights
14+
`wᵢ`. For each `i : ι`, we thus have an affine map `P →ᵃ[k] k`, namely `q ↦ wᵢ`. This family of
15+
maps is known as the family of barycentric coordinates. It is defined in this file.
16+
17+
## The construction
18+
19+
Fixing `i : ι`, and allowing `j : ι` to range over the values `j ≠ i`, we obtain a basis `bᵢ` of `V`
20+
defined by `bᵢ j = p j -ᵥ p i`. Let `fᵢ j : V →ₗ[k] k` be the corresponding dual basis and let
21+
`fᵢ = ∑ j, fᵢ j : V →ₗ[k] k` be the corresponding "sum of all coordinates" form. Then the `i`th
22+
barycentric coordinate of `q : P` is `1 - fᵢ (q -ᵥ p i)`.
23+
24+
## Main definitions
25+
26+
* `barycentric_coord`: the map `P →ᵃ[k] k` corresponding to `i : ι`.
27+
* `barycentric_coord_apply_eq`: the behaviour of `barycentric_coord i` on `p i`.
28+
* `barycentric_coord_apply_neq`: the behaviour of `barycentric_coord i` on `p j` when `j ≠ i`.
29+
* `barycentric_coord_apply`: the behaviour of `barycentric_coord i` on `p j` for general `j`.
30+
* `barycentric_coord_apply_combination`: the characterisation of `barycentric_coord i` in terms
31+
of affine combinations, i.e., `barycentric_coord i (w₀ p₀ + w₁ p₁ + ⋯) = wᵢ`.
32+
33+
## TODO
34+
35+
* Construct the affine equivalence between `P` and `{ f : ι →₀ k | f.sum = 1 }`.
36+
37+
-/
38+
39+
open_locale affine big_operators
40+
open set
41+
42+
universes u₁ u₂ u₃ u₄
43+
44+
variables {ι : Type u₁} {k : Type u₂} {V : Type u₃} {P : Type u₄}
45+
variables [ring k] [add_comm_group V] [module k V] [affine_space V P]
46+
variables {p : ι → P} (h_ind : affine_independent k p) (h_tot : affine_span k (range p) = ⊤)
47+
include V h_ind h_tot
48+
49+
/-- Given an affine-independent family of points spanning the point space `P`, if we single out one
50+
member of the family, we obtain a basis for the model space `V`.
51+
52+
The basis correpsonding to the singled-out member `i : ι` is indexed by `{j : ι // j ≠ i}` and its
53+
`j`th element is `p j -ᵥ p i`. (See `basis_of_aff_ind_span_eq_top_apply`.) -/
54+
noncomputable def basis_of_aff_ind_span_eq_top (i : ι) : basis {j : ι // j ≠ i} k V :=
55+
basis.mk ((affine_independent_iff_linear_independent_vsub k p i).mp h_ind)
56+
begin
57+
suffices : submodule.span k (range (λ (j : {x // x ≠ i}), p ↑j -ᵥ p i)) = vector_span k (range p),
58+
{ rw [this, ← direction_affine_span, h_tot, affine_subspace.direction_top], },
59+
conv_rhs { rw ← image_univ, },
60+
rw vector_span_image_eq_span_vsub_set_right_ne k p (mem_univ i),
61+
congr,
62+
ext v,
63+
simp,
64+
end
65+
66+
local notation `basis_of` := basis_of_aff_ind_span_eq_top h_ind h_tot
67+
68+
@[simp] lemma basis_of_aff_ind_span_eq_top_apply (i : ι) (j : {j : ι // j ≠ i}) :
69+
basis_of i j = p ↑j -ᵥ p i :=
70+
by simp [basis_of_aff_ind_span_eq_top]
71+
72+
/-- The `i`th barycentric coordinate of a point. -/
73+
noncomputable def barycentric_coord (i : ι) : P →ᵃ[k] k :=
74+
{ to_fun := λ q, 1 - (basis_of i).sum_coords (q -ᵥ p i),
75+
linear := -(basis_of i).sum_coords,
76+
map_vadd' := λ q v, by rw [vadd_vsub_assoc, linear_map.map_add, vadd_eq_add, linear_map.neg_apply,
77+
sub_add_eq_sub_sub_swap, add_comm, sub_eq_add_neg], }
78+
79+
@[simp] lemma barycentric_coord_apply_eq (i : ι) :
80+
barycentric_coord h_ind h_tot i (p i) = 1 :=
81+
by simp only [barycentric_coord, basis.coe_sum_coords, linear_equiv.map_zero, linear_equiv.coe_coe,
82+
sub_zero, affine_map.coe_mk, finsupp.sum_zero_index, vsub_self]
83+
84+
@[simp] lemma barycentric_coord_apply_neq (i j : ι) (h : j ≠ i) :
85+
barycentric_coord h_ind h_tot i (p j) = 0 :=
86+
by rw [barycentric_coord, affine_map.coe_mk, ← subtype.coe_mk j h,
87+
← basis_of_aff_ind_span_eq_top_apply h_ind h_tot i ⟨j, h⟩, basis.sum_coords_self_apply, sub_self]
88+
89+
lemma barycentric_coord_apply [decidable_eq ι] (i j : ι) :
90+
barycentric_coord h_ind h_tot i (p j) = if i = j then 1 else 0 :=
91+
by { cases eq_or_ne i j; simp [h.symm], simp [h], }
92+
93+
@[simp] lemma barycentric_coord_apply_combination
94+
{s : finset ι} {i : ι} (hi : i ∈ s) {w : ι → k} (hw : s.sum w = 1) :
95+
barycentric_coord h_ind h_tot i (s.affine_combination p w) = w i :=
96+
begin
97+
classical,
98+
simp only [barycentric_coord_apply, hi, finset.affine_combination_eq_linear_combination, if_true,
99+
hw, mul_boole, function.comp_app, smul_eq_mul, s.sum_ite_eq, s.map_affine_combination p w hw],
100+
end

src/linear_algebra/affine_space/basic.lean

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ files:
2525
* `affine_equiv`: an equivalence between affine spaces that preserves the affine structure;
2626
* `affine_subspace`: a subset of an affine space closed w.r.t. affine combinations of points;
2727
* `affine_combination`: an affine combination of points;
28-
* `affine_independent`: affine independent set of points.
28+
* `affine_independent`: affine independent set of points;
29+
* `barycentric_coord`: the barycentric coordinate of a point.
2930
3031
## TODO
3132
@@ -34,9 +35,6 @@ Some key definitions are not yet present.
3435
* Affine frames. An affine frame might perhaps be represented as an `affine_equiv` to a `finsupp`
3536
(in the general case) or function type (in the finite-dimensional case) that gives the
3637
coordinates, with appropriate proofs of existence when `k` is a field.
37-
38-
* Although results on affine combinations implicitly provide barycentric frames and coordinates,
39-
there is no explicit representation of the map from a point to its coordinates.
4038
-/
4139

4240
localized "notation `affine_space` := add_torsor" in affine

src/linear_algebra/basis.lean

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Johannes Hölzl, Mario Carneiro, Alexander Bentkamp
55
-/
66
import algebra.big_operators.finsupp
7+
import algebra.big_operators.finprod
78
import data.fintype.card
89
import linear_algebra.finsupp
910
import linear_algebra.linear_independent
@@ -157,14 +158,42 @@ with respect to the basis `b`.
157158
finite-dimensional spaces it is the `ι`th basis vector of the dual space.
158159
-/
159160
@[simps]
160-
def coord (i : ι) : M →ₗ[R] R := (finsupp.lapply i) ∘ₗ ↑b.repr
161+
def coord : M →ₗ[R] R := (finsupp.lapply i) ∘ₗ ↑b.repr
161162

162163
lemma forall_coord_eq_zero_iff {x : M} :
163164
(∀ i, b.coord i x = 0) ↔ x = 0 :=
164165
iff.trans
165166
(by simp only [b.coord_apply, finsupp.ext_iff, finsupp.zero_apply])
166167
b.repr.map_eq_zero_iff
167168

169+
/-- The sum of the coordinates of an element `m : M` with respect to a basis. -/
170+
noncomputable def sum_coords : M →ₗ[R] R :=
171+
finsupp.lsum ℕ (λ i, linear_map.id) ∘ₗ (b.repr : M →ₗ[R] ι →₀ R)
172+
173+
@[simp] lemma coe_sum_coords : (b.sum_coords : M → R) = λ m, (b.repr m).sum (λ i, id) :=
174+
rfl
175+
176+
lemma coe_sum_coords_eq_finsum : (b.sum_coords : M → R) = λ m, ∑ᶠ i, b.coord i m :=
177+
begin
178+
ext m,
179+
simp only [basis.sum_coords, basis.coord, finsupp.lapply_apply, linear_map.id_coe,
180+
linear_equiv.coe_coe, function.comp_app, finsupp.coe_lsum, linear_map.coe_comp,
181+
finsum_eq_sum _ (b.repr m).finite_support, finsupp.sum, finset.finite_to_set_to_finset,
182+
id.def, finsupp.fun_support_eq],
183+
end
184+
185+
@[simp] lemma coe_sum_coords_of_fintype [fintype ι] : (b.sum_coords : M → R) = ∑ i, b.coord i :=
186+
begin
187+
ext m,
188+
simp only [sum_coords, finsupp.sum_fintype, linear_map.id_coe, linear_equiv.coe_coe, coord_apply,
189+
id.def, fintype.sum_apply, implies_true_iff, eq_self_iff_true, finsupp.coe_lsum,
190+
linear_map.coe_comp],
191+
end
192+
193+
@[simp] lemma sum_coords_self_apply : b.sum_coords (b i) = 1 :=
194+
by simp only [basis.sum_coords, linear_map.id_coe, linear_equiv.coe_coe, id.def, basis.repr_self,
195+
function.comp_app, finsupp.coe_lsum, linear_map.coe_comp, finsupp.sum_single_index]
196+
168197
end coord
169198

170199
section ext

0 commit comments

Comments
 (0)