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

Commit 6dcad02

Browse files
feat(linear_algebra/lagrange): Add recurrence formula for Lagrange polynomials (#11762)
I have also changed `interpolate` to take in a function `f : F → F` instead of `f : s → F`, since this makes the statement of the theorem nicer.
1 parent 853192c commit 6dcad02

File tree

2 files changed

+81
-24
lines changed

2 files changed

+81
-24
lines changed

docs/undergrad.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,8 @@ Numerical Analysis:
648648
rate of convergence: ''
649649
application to the calculation of multiple integrals: ''
650650
Approximation of numerical functions:
651-
Lagrange interpolation: ''
652-
Lagrange polynomial of a function at (n + 1) points: ''
651+
Lagrange interpolation: 'lagrange.interpolate'
652+
Lagrange polynomial of a function at (n + 1) points: 'lagrange.interpolate'
653653
estimation of the error: ''
654654
Ordinary differential equations:
655655
numerical aspects of Cauchy's problem: ''

src/linear_algebra/lagrange.lean

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import ring_theory.polynomial.basic
1414
1515
* `lagrange.basis s x` where `s : finset F` and `x : F`: the Lagrange basis polynomial
1616
that evaluates to `1` at `x` and `0` at other elements of `s`.
17-
* `lagrange.interpolate s f` where `s : finset F` and `f : s → F`: the Lagrange interpolant
17+
* `lagrange.interpolate s f` where `s : finset F` and `f : F → F`: the Lagrange interpolant
1818
that evaluates to `f x` at `x` for `x ∈ s`.
19-
2019
-/
2120

2221
noncomputable theory
@@ -38,6 +37,9 @@ def basis (x : F) : polynomial F :=
3837
@[simp] theorem basis_empty (x : F) : basis ∅ x = 1 :=
3938
rfl
4039

40+
@[simp] theorem basis_singleton_self (x : F) : basis {x} x = 1 :=
41+
by rw [basis, finset.erase_singleton, finset.prod_empty]
42+
4143
@[simp] theorem eval_basis_self (x : F) : (basis s x).eval x = 1 :=
4244
begin
4345
rw [basis, ← coe_eval_ring_hom, (eval_ring_hom x).map_prod, coe_eval_ring_hom,
@@ -77,26 +79,26 @@ begin
7779
{ rw ← pow_one (X : polynomial F) at hz, exact X_pow_sub_C_ne_zero zero_lt_one _ hz } }
7880
end
7981

80-
variables (f : s → F)
82+
variables (f : F → F)
8183

82-
/-- Lagrange interpolation: given a finset `s` and a function `f : s → F`,
84+
/-- Lagrange interpolation: given a finset `s` and a function `f : F → F`,
8385
`interpolate s f` is the unique polynomial of degree `< s.card`
8486
that takes value `f x` on all `x` in `s`. -/
8587
def interpolate : polynomial F :=
86-
∑ x in s.attach, C (f x) * basis s x
88+
∑ x in s, C (f x) * basis s x
8789

8890
@[simp] theorem interpolate_empty (f) : interpolate (∅ : finset F) f = 0 :=
8991
rfl
9092

91-
@[simp] theorem eval_interpolate (x) (H : x ∈ s) : eval x (interpolate s f) = f ⟨x, H⟩ :=
93+
@[simp] theorem interpolate_singleton (f) (x : F) : interpolate {x} f = C (f x) :=
94+
by rw [interpolate, finset.sum_singleton, basis_singleton_self, mul_one]
95+
96+
@[simp] theorem eval_interpolate (x) (H : x ∈ s) : eval x (interpolate s f) = f x :=
9297
begin
93-
rw [interpolate,
94-
← coe_eval_ring_hom, (eval_ring_hom x).map_sum, coe_eval_ring_hom,
95-
finset.sum_eq_single (⟨x, H⟩ : { x // x ∈ s })],
96-
{ rw [eval_mul, eval_C, subtype.coe_mk, eval_basis_self, mul_one] },
97-
{ rintros ⟨y, hy⟩ _ hyx, rw [eval_mul, subtype.coe_mk, eval_basis_ne s y x H, mul_zero],
98-
{ rintros rfl, exact hyx rfl } },
99-
{ intro h, exact absurd (finset.mem_attach _ _) h }
98+
rw [interpolate, ←coe_eval_ring_hom, ring_hom.map_sum, coe_eval_ring_hom, finset.sum_eq_single x],
99+
{ simp },
100+
{ intros y hy hxy, simp [eval_basis_ne s y x H hxy.symm] },
101+
{ intro h, exact (h H).elim }
100102
end
101103

102104
theorem degree_interpolate_lt : (interpolate s f).degree < s.card :=
@@ -107,11 +109,26 @@ calc (C (f b) * basis s b).degree
107109
... ≤ 0 + (basis s b).degree : add_le_add_right degree_C_le _
108110
... = (basis s b).degree : zero_add _
109111
... ≤ (basis s b).nat_degree : degree_le_nat_degree
110-
... = (s.card - 1 : ℕ) : by { rw nat_degree_basis s b b.2 }
112+
... = (s.card - 1 : ℕ) : by { rwa nat_degree_basis }
111113
... < s.card : with_bot.coe_lt_coe.2 (nat.pred_lt $ mt finset.card_eq_zero.1 H)
112114

115+
theorem degree_interpolate_erase {x} (hx : x ∈ s) :
116+
(interpolate (s.erase x) f).degree < (s.card - 1 : ℕ) :=
117+
begin
118+
convert degree_interpolate_lt (s.erase x) f,
119+
rw [finset.card_erase_of_mem hx, nat.pred_eq_sub_one]
120+
end
121+
122+
theorem interpolate_eq_of_eval_eq (f g : F → F) {s : finset F} (hs : ∀ x ∈ s, f x = g x) :
123+
interpolate s f = interpolate s g :=
124+
begin
125+
rw [interpolate, interpolate],
126+
refine finset.sum_congr rfl (λ x hx, _),
127+
rw hs x hx,
128+
end
129+
113130
/-- Linear version of `interpolate`. -/
114-
def linterpolate : (s → F) →ₗ[F] polynomial F :=
131+
def linterpolate : (F → F) →ₗ[F] polynomial F :=
115132
{ to_fun := interpolate s,
116133
map_add' := λ f g, by { simp_rw [interpolate, ← finset.sum_add_distrib, ← add_mul, ← C_add],
117134
refl },
@@ -147,6 +164,13 @@ eq_of_sub_eq_zero $ eq_zero_of_eval_eq_zero s'
147164
(lt_of_le_of_lt (degree_sub_le f g) $ max_lt hf hg)
148165
(λ x hx, by rw [eval_sub, hfg x hx, sub_self])
149166

167+
theorem eq_interpolate_of_eval_eq {g : polynomial F} (hg : g.degree < s.card)
168+
(hgf : ∀ x ∈ s, g.eval x = f x) : interpolate s f = g :=
169+
eq_of_eval_eq s (degree_interpolate_lt _ _) hg $ λ x hx, begin
170+
rw hgf x hx,
171+
exact eval_interpolate _ _ _ hx,
172+
end
173+
150174
theorem eq_interpolate (f : polynomial F) (hf : f.degree < s.card) :
151175
interpolate s (λ x, f.eval x) = f :=
152176
eq_of_eval_eq s (degree_interpolate_lt s _) hf $ λ x hx, eval_interpolate s _ x hx
@@ -156,12 +180,45 @@ of degree less than `s.card`. -/
156180
def fun_equiv_degree_lt : degree_lt F s.card ≃ₗ[F] (s → F) :=
157181
{ to_fun := λ f x, f.1.eval x,
158182
map_add' := λ f g, funext $ λ x, eval_add,
159-
map_smul' := λ c f, funext $ λ x, by
160-
{ change eval ↑x (c • f).val = (c • λ (x : s), eval ↑x f.val) x,
161-
rw [pi.smul_apply, smul_eq_mul, ← @eval_C F c _ x,
162-
← eval_mul, eval_C, C_mul'], refl },
163-
inv_fun := λ f, ⟨interpolate s f, mem_degree_lt.2 $ degree_interpolate_lt s f⟩,
164-
left_inv := λ f, subtype.eq $ eq_interpolate s f $ mem_degree_lt.1 f.2,
165-
right_inv := λ f, funext $ λ ⟨x, hx⟩, eval_interpolate s f x hx }
183+
map_smul' := λ c f, funext $ by simp,
184+
inv_fun := λ f, ⟨interpolate s (λ x, if hx : x ∈ s then f ⟨x, hx⟩ else 0),
185+
mem_degree_lt.2 $ degree_interpolate_lt _ _⟩,
186+
left_inv := λ f, begin apply subtype.eq,
187+
simp only [subtype.coe_mk, subtype.val_eq_coe, dite_eq_ite],
188+
convert eq_interpolate s f (mem_degree_lt.1 f.2) using 1,
189+
rw interpolate_eq_of_eval_eq,
190+
intros x hx,
191+
rw if_pos hx end,
192+
right_inv := λ f, funext $ λ ⟨x, hx⟩, begin
193+
convert eval_interpolate s _ x hx,
194+
simp_rw dif_pos hx end }
195+
196+
theorem interpolate_eq_interpolate_erase_add {x y : F} (hx : x ∈ s) (hy : y ∈ s) (hxy : x ≠ y) :
197+
interpolate s f =
198+
C (y - x)⁻¹ * ((X - C x) * interpolate (s.erase x) f + (C y - X) * interpolate (s.erase y) f) :=
199+
begin
200+
refine eq_interpolate_of_eval_eq _ _ _ (λ z hz, _),
201+
{ rw [degree_mul, degree_C (inv_ne_zero (sub_ne_zero.2 hxy.symm)), zero_add],
202+
refine lt_of_le_of_lt (degree_add_le _ _) (max_lt _ _),
203+
{ rw [degree_mul, degree_X_sub_C],
204+
convert (with_bot.add_lt_add_iff_left (with_bot.coe_ne_bot _)).2
205+
(degree_interpolate_erase s f hx),
206+
simp [nat.one_add, nat.sub_one, nat.succ_pred_eq_of_pos (finset.card_pos.2 ⟨x, hx⟩)] },
207+
{ rw [degree_mul, ←neg_sub, degree_neg, degree_X_sub_C],
208+
convert (with_bot.add_lt_add_iff_left (with_bot.coe_ne_bot _)).2
209+
(degree_interpolate_erase s f hy),
210+
simp [nat.one_add, nat.sub_one, nat.succ_pred_eq_of_pos (finset.card_pos.2 ⟨y, hy⟩)] } },
211+
{ by_cases hzx : z = x,
212+
{ simp [hzx, eval_interpolate (s.erase y) f x (finset.mem_erase_of_ne_of_mem hxy hx),
213+
inv_mul_eq_iff_eq_mul₀ (sub_ne_zero_of_ne hxy.symm)] },
214+
{ by_cases hzy : z = y,
215+
{ simp [hzy, eval_interpolate (s.erase x) f y (finset.mem_erase_of_ne_of_mem hxy.symm hy),
216+
inv_mul_eq_iff_eq_mul₀ (sub_ne_zero_of_ne hxy.symm)] },
217+
{ simp only [eval_interpolate (s.erase x) f z (finset.mem_erase_of_ne_of_mem hzx hz),
218+
eval_interpolate (s.erase y) f z (finset.mem_erase_of_ne_of_mem hzy hz),
219+
inv_mul_eq_iff_eq_mul₀ (sub_ne_zero_of_ne hxy.symm), eval_mul, eval_C, eval_add,
220+
eval_sub, eval_X],
221+
ring } } }
222+
end
166223

167224
end lagrange

0 commit comments

Comments
 (0)