|
| 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 |
0 commit comments