Interpolation constructs a polynomial from sampled values. On the Chebyshev extrema grid, a discrete cosine transform gives its coefficients, while the barycentric formula evaluates it directly from the samples.
2.4.1 Interpolation and the cosine grid
For distinct nodes \(x_0,\ldots ,x_N\), the cardinal polynomials are \(\ell _j(X)=\prod _{i\ne j}(X-x_i)/(x_j-x_i)\). Their values at the nodes are \(\ell _j(x_i)=\delta _{ij}\), so \(\sum _j f(x_j)\ell _j\) interpolates the data (Theorem 2.4.15). We now choose the cosine grid.
For a positive natural order \(N\) and a natural angular index \(j\), define \(x_{N,j}=\cos (j\pi /N)\). The extrema grid consists of \(0\le j\le N\). Reference: [ATAP, Chapter 4].
Lean Formalisation
def Polynomial.Chebyshev.classicalNode (N : { n // 0 < n }) (j : ℕ) : ℝ
For \(N\ge 0\), index the grid by \(0\le j\le N\). When \(N{\gt}0\) its points are \(x_{N,j}=\cos (j\pi /N)\). For \(N=0\) there is one node, \(x_{0,0}=1\).
/-- Finite extrema grid, with the separate singleton at `1` for order zero. -/
noncomputable def extremaGridNode (N : ℕ) (j : Fin (N + 1)) : ℝ :=
if h : N = 0 then 1 else classicalNode ⟨N, Nat.pos_of_ne_zero h⟩ j
For a finite-grid index \(j\), let \(\ell _{N,j}\) be its classical Lagrange cardinal polynomial. At order zero it is the constant polynomial \(1\). Reference: [ATAP, Chapter 4].
/-- Classical cardinal polynomial on the finite extrema grid (ATAP Chapter 4).
For the singleton grid it is the constant one. -/
@[expose] noncomputable def extremaCardinal (N : ℕ) (j : Fin (N + 1)) : ℂ[X] :=
if h : N = 0 then 1 else
Lagrange.classicalBasis (Finset.range (N + 1))
(fun i ↦ (classicalNode ⟨N, Nat.pos_of_ne_zero h⟩ i : ℂ)) j
(Lagrange.BasisInput.of_injOn (Complex.ofReal_injective.comp_injOn (strictAntiOn_classicalNode ⟨N,Nat.pos_of_ne_zero h⟩).injOn) (Finset.mem_range.mpr j.isLt))
For positive order the cardinal polynomials are the classical Lagrange products; for order zero the single polynomial is \(1\). For every order, \(\ell _{N,i}(x_{N,j})=\delta _{ij}\).
theorem Polynomial.Chebyshev.eval_extremaCardinal (N : ℕ) (i j : Fin (N + 1)) :
Polynomial.eval (↑(Polynomial.Chebyshev.extremaGridNode N j)) (Polynomial.Chebyshev.extremaCardinal N i) =
if i = j then 1 else 0
Lean proof
/-- Cardinal values on the entire finite grid. -/
theorem eval_extremaCardinal (N : ℕ) (i j : Fin (N + 1)) :
(extremaCardinal N i).eval (extremaGridNode N j : ℂ) = if i = j then 1 else 0 := by
by_cases hN : N = 0
· subst N
have hij : i = j := Fin.ext (by omega)
simp [extremaCardinal_zero, hij]
· rw [extremaCardinal_positive ⟨N,Nat.pos_of_ne_zero hN⟩,
extremaGridNode_positive ⟨N,Nat.pos_of_ne_zero hN⟩]
by_cases hij : i = j
· subst j
rw [ite_eq_left rfl]
exact Lagrange.eval_classicalBasis_self (Finset.range (N+1))
(fun k ↦ (classicalNode ⟨N,Nat.pos_of_ne_zero hN⟩ k : ℂ)) i.val _
· rw [ite_eq_right hij]
exact Lagrange.eval_classicalBasis_of_ne
(v := fun k ↦ (classicalNode ⟨N,Nat.pos_of_ne_zero hN⟩ k : ℂ)) _ (fun h ↦ hij (Fin.ext h))
(Finset.mem_range.mpr j.isLt)
For \(N\ge 1\), let \(I_Nf\in \mathbb {C}[X]\) be the Lagrange interpolant of \(f:\mathbb {R}\to \mathbb {C}\) at the \(N+1\) distinct Chebyshev extrema \(x_j=\cos (j\pi /N)\), \(0\le j\le N\). For \(N=0\), define \(I_0f\) to be the constant polynomial \(f(1)\).
theorem Polynomial.Chebyshev.eval_extremaInterpolant_classicalNode (N : { n // 0 < n }) (f : ℝ → ℂ) (j : Fin (↑N + 1)) :
Polynomial.eval (↑(Polynomial.Chebyshev.classicalNode N ↑j)) (Polynomial.Chebyshev.extremaInterpolant (↑N) f) =
f (Polynomial.Chebyshev.classicalNode N ↑j)
Lean proof
/-- Interpolation at a node on the classical positive-order grid. -/
theorem eval_extremaInterpolant_classicalNode (N : {n : ℕ // 0 < n})
(f : ℝ → ℂ) (j : Fin (N.val + 1)) :
(extremaInterpolant N.val f).eval (classicalNode N j : ℂ) = f (classicalNode N j) := by
rw [extremaInterpolant_positive N]
exact Lagrange.eval_classicalInterpolate
(s := Finset.range (N.val+1)) (v := fun k ↦ (classicalNode N k : ℂ))
_ _ ⟨j.val, Finset.mem_range.mpr j.isLt⟩
/-- The extrema interpolant has degree at most `N`. -/
theorem degree_extremaInterpolant_lt (N : ℕ) (f : ℝ → ℂ) :
(extremaInterpolant N f).degree < (N + 1 : ℕ) := by
by_cases h : N = 0
· subst N
rw [extremaInterpolant_zero]
simpa using (degree_C_lt (a := f 1))
· rw [extremaInterpolant_positive ⟨N,Nat.pos_of_ne_zero h⟩]
simpa only [Lagrange.classicalInterpolate,Finset.card_range] using
Lagrange.degree_interpolate_lt (v := fun j ↦ (classicalNode ⟨N,Nat.pos_of_ne_zero h⟩ j : ℂ))
(fun j ↦ f (classicalNode ⟨N,Nat.pos_of_ne_zero h⟩ j)) (Complex.ofReal_injective.comp_injOn (strictAntiOn_classicalNode ⟨N,Nat.pos_of_ne_zero h⟩).injOn)
/-- Finite-grid points are pairwise distinct, including the singleton grid. -/
theorem extremaGridNode_injective (N : ℕ) : Function.Injective (extremaGridNode N) := by
by_cases h : N = 0
· subst N
intro i j _
exact Fin.ext (by omega)
· intro i j hij
simp only [extremaGridNode_positive ⟨N,Nat.pos_of_ne_zero h⟩] at hij
apply Fin.ext
exact (strictAntiOn_classicalNode ⟨N,Nat.pos_of_ne_zero h⟩).injOn
(Finset.mem_range.mpr i.isLt) (Finset.mem_range.mpr j.isLt) hij
For a finite index set \(s\) and field-valued nodes \(v\), define the admissible indices to be those \(i\) satisfying \(v_i\ne v_j\) for every \(j\in s\setminus \{ i\} \). An admissible index need not belong to \(s\).
Lean Formalisation
inductive Lagrange.BasisInput.{u_1, u_2} {F : Type u_1} {ι : Type u_2} [DecidableEq ι] (s : Finset ι) (v : ι → F) (i : ι) : Prop
Lean definition
/-- Precisely the nonzero denominators of a normalized nodal product. -/
structure BasisInput (s : Finset ι) (v : ι → F) (i : ι) : Prop where
separated : ∀ j ∈ s.erase i, v i ≠ v j
If the nodes \(v_i\) are distinct on \(s\), then every \(i\in s\) is admissible: \(v_i-v_j\ne 0\) for \(j\in s\setminus \{ i\} \). For identity nodes on a finite subset \(s\) of a field, every field element \(x\) is admissible, since \(x-y\ne 0\) for \(y\in s\setminus \{ x\} \); this includes \(x\notin s\).
Lean Formalisation
theorem Lagrange.BasisInput.of_injOn.{u_1, u_2} {F : Type u_1} {ι : Type u_2} [DecidableEq ι] {s : Finset ι} {v : ι → F}
(hv : Set.InjOn v ↑s) {i : ι} (hi : i ∈ s) : Lagrange.BasisInput s v i
Lean proof
/-- Distinct interpolation nodes supply classical basis inputs. -/
theorem BasisInput.of_injOn {s : Finset ι} {v : ι → F}
(hv : Set.InjOn v s) {i : ι} (hi : i ∈ s) : BasisInput s v i :=
⟨fun _j hj h ↦ (Finset.mem_erase.mp hj).1 (hv (Finset.mem_erase.mp hj).2 hi h.symm)⟩
theorem Lagrange.BasisInput.id.{u_1} {F : Type u_1} [DecidableEq F] (s : Finset F) (x : F) : Lagrange.BasisInput s id x
Lean proof
/-- For identity nodes the normalized product is valid even off the node set. -/
theorem BasisInput.id [DecidableEq F] (s : Finset F) (x : F) : BasisInput s id x := by
classical
exact ⟨fun _j hj h ↦ (Finset.mem_erase.mp hj).1 h.symm⟩
For an admissible index \(i\) of Definition 2.4.10, define \(\ell _i(X)=\prod _{j\in s\setminus \{ i\} }(X-v_j)/(v_i-v_j)\). When \(i\notin s\) this is the normalized nodal product, extending the cardinal-polynomial construction. Reference: [DLMF, 3.3(i)].
Lean Formalisation
def Lagrange.classicalBasis.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι) (v : ι → F)
(i : ι) (_d : Lagrange.BasisInput s v i) : Polynomial F
Lean definition
/-- The classical normalized nodal product (DLMF §3.3(i)). -/
noncomputable def classicalBasis (s : Finset ι) (v : ι → F) (i : ι)
(_d : BasisInput s v i) : F[X] := Lagrange.basis s v i
The polynomial is the displayed product, has \(\ell _i(v_i)=1\), and vanishes at \(v_j\) for \(j\in s\), \(j\ne i\). In particular it is nonzero.
Lean Formalisation
theorem Lagrange.classicalBasis_eq_product.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (d : Lagrange.BasisInput s v i) :
Lagrange.classicalBasis s v i d = ∏ j ∈ s.erase i, Polynomial.C (v i - v j)⁻¹ * (Polynomial.X - Polynomial.C (v j))
Lean proof
/-- Product formula, with every denominator certified nonzero by the input. -/
theorem classicalBasis_eq_product (s : Finset ι) (v : ι → F) (i : ι)
(d : BasisInput s v i) :
classicalBasis s v i d =
∏ j ∈ s.erase i, Polynomial.C ((v i - v j)⁻¹) * (X - C (v j)) := rfl
theorem Lagrange.eval_classicalBasis_self.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (d : Lagrange.BasisInput s v i) : Polynomial.eval (v i) (Lagrange.classicalBasis s v i d) = 1
Lean proof
/-- The normalized nodal product takes value one at its normalization point. -/
theorem eval_classicalBasis_self (s : Finset ι) (v : ι → F) (i : ι)
(d : BasisInput s v i) : (classicalBasis s v i d).eval (v i) = 1 := by
simp only [classicalBasis, Lagrange.basis, eval_prod]
exact Finset.prod_eq_one fun j hj ↦ eval_basisDivisor_left_of_ne (d.separated j hj)
theorem Lagrange.eval_classicalBasis_of_ne.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] {s : Finset ι}
{v : ι → F} {i j : ι} (d : Lagrange.BasisInput s v i) (hij : i ≠ j) (hj : j ∈ s) :
Polynomial.eval (v j) (Lagrange.classicalBasis s v i d) = 0
Lean proof
/-- Cardinal vanishing at every other interpolation node. -/
theorem eval_classicalBasis_of_ne {s : Finset ι} {v : ι → F} {i j : ι}
(d : BasisInput s v i) (hij : i ≠ j) (hj : j ∈ s) :
(classicalBasis s v i d).eval (v j) = 0 := eval_basis_of_ne hij hj
theorem Lagrange.classicalBasis_ne_zero.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (d : Lagrange.BasisInput s v i) : Lagrange.classicalBasis s v i d ≠ 0
Lean proof
/-- A classical basis polynomial is nonzero. -/
theorem classicalBasis_ne_zero (s : Finset ι) (v : ι → F) (i : ι)
(d : BasisInput s v i) : classicalBasis s v i d ≠ 0 := by
intro h
have e := eval_classicalBasis_self s v i d
rw [h, eval_zero] at e
exact zero_ne_one e
For a finite set of natural indices \(S\), real nodes \(v_i\), and any index \(j\) with \(v_j\ne v_i\) for every \(i\in S\setminus \{ j\} \), the normalized cardinal product has the same value at a real point whether computed over \(\mathbb R\) or over \(\mathbb C\). The same separation condition holds over \(\mathbb C\). The index \(j\) need not belong to \(S\).
Lean Formalisation
theorem Polynomial.Chebyshev.complex_basisInput {s : Finset ℕ} {v : ℕ → ℝ} {j : ℕ} (d : Lagrange.BasisInput s v j) :
Lagrange.BasisInput s (fun i => ↑(v i)) j
Lean proof
/-- Real nodes give separated complex nodes whenever the real product is classical. -/
theorem complex_basisInput {s : Finset ℕ} {v : ℕ → ℝ} {j : ℕ}
(d : Lagrange.BasisInput s v j) :
Lagrange.BasisInput s (fun i ↦ (v i : ℂ)) j :=
⟨fun i hi h ↦ d.separated i hi (Complex.ofReal_injective h)⟩
theorem Lagrange.eval_classicalBasis_complex (s : Finset ℕ) (v : ℕ → ℝ) (j : ℕ) (d : Lagrange.BasisInput s v j) (x : ℝ) :
Polynomial.eval (↑x) (Lagrange.classicalBasis s (fun i => ↑(v i)) j ⋯) =
↑(Polynomial.eval x (Lagrange.classicalBasis s v j d))
Lean proof
/-- Complex evaluation of a real classical normalized nodal product.
The normalization index need not belong to the interpolation set (DLMF §3.3(i)). -/
theorem Lagrange.eval_classicalBasis_complex (s : Finset ℕ) (v : ℕ → ℝ) (j : ℕ)
(d : Lagrange.BasisInput s v j) (x : ℝ) :
(Lagrange.classicalBasis s (fun i ↦ (v i : ℂ)) j
(Polynomial.Chebyshev.complex_basisInput d)).eval (x : ℂ) =
(((Lagrange.classicalBasis s v j d).eval x : ℝ) : ℂ) := by
simp [Lagrange.classicalBasis, Lagrange.basis, Lagrange.basisDivisor,
Polynomial.eval_prod]
For a finite set \(s\) of indices and distinct field-valued nodes \(v_i\), there are Lagrange polynomials \(\ell _i\) with \(\ell _i(v_j)=\delta _{ij}\) for \(i,j\in s\). Each \(\ell _i\) is nonzero of degree \(|s|-1\), and every polynomial of degree less than \(|s|\) is its Lagrange interpolant.
theorem Lagrange.eq_sum_classicalBasis.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] {s : Finset ι}
{v : ι → F} (hv : Set.InjOn v ↑s) {p : Polynomial F} (hp : p.degree < ↑s.card) :
p = ∑ i, Polynomial.C (Polynomial.eval (v ↑i) p) * Lagrange.classicalBasis s v ↑i ⋯
Lean proof
/-- Exact interpolation with classical basis inputs (DLMF §3.3(i)). -/
theorem eq_sum_classicalBasis {s : Finset ι} {v : ι → F}
(hv : Set.InjOn v s) {p : F[X]} (hp : p.degree < s.card) :
p = ∑ i : s, C (p.eval (v i)) *
classicalBasis s v i (BasisInput.of_injOn hv i.property) := by
classical
calc
p = ∑ i ∈ s, C (p.eval (v i)) * Lagrange.basis s v i := by
simpa only [interpolate_apply] using eq_interpolate hv hp
_ = _ := by
exact (Finset.sum_coe_sort s (fun i ↦ C (p.eval (v i)) * Lagrange.basis s v i)).symm
For an admissible index \(i\) of Definition 2.4.10, define \(\omega _i=\prod _{j\in s\setminus \{ i\} }(v_i-v_j)^{-1}\). This also permits \(i\notin s\) whenever all displayed denominators are nonzero. Reference: [DLMF, 3.3(i)].
Lean Formalisation
def Lagrange.classicalNodalWeight.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (_d : Lagrange.BasisInput s v i) : F
Lean definition
/-- Nodal product weight with its precise classical denominator domain. -/
noncomputable def classicalNodalWeight (s : Finset ι) (v : ι → F) (i : ι)
(_d : BasisInput s v i) : F := nodalWeight s v i
The weight is the displayed product and is nonzero. Writing \(q(X)=\prod _{j\in s}(X-v_j)\), if \(i\in s\) then \(q'(v_i)\ne 0\) and \(\omega _i=1/q'(v_i)\). For \(i\in s\) and \(x\ne v_i\), \(\ell _i(x)=q(x)\omega _i/(x-v_i)\).
Lean Formalisation
theorem Lagrange.classicalNodalWeight_apply.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (d : Lagrange.BasisInput s v i) :
Lagrange.classicalNodalWeight s v i d = ∏ j ∈ s.erase i, (v i - v j)⁻¹
Lean proof
/-- Classical product formula, including valid off-node extensions. -/
theorem classicalNodalWeight_apply (s : Finset ι) (v : ι → F) (i : ι)
(d : BasisInput s v i) :
classicalNodalWeight s v i d = ∏ j ∈ s.erase i, (v i - v j)⁻¹ := rfl
theorem Lagrange.classicalNodalWeight_ne_zero.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (i : ι) (d : Lagrange.BasisInput s v i) : Lagrange.classicalNodalWeight s v i d ≠ 0
Lean proof
/-- A classical nodal weight cannot vanish. -/
theorem classicalNodalWeight_ne_zero (s : Finset ι) (v : ι → F) (i : ι)
(d : BasisInput s v i) : classicalNodalWeight s v i d ≠ 0 := by
apply Finset.prod_ne_zero_iff.mpr
intro j hj
exact inv_ne_zero (sub_ne_zero.mpr (d.separated j hj))
theorem Lagrange.classicalNodalWeight_eq_derivative.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι]
{s : Finset ι} {v : ι → F} {i : ι} (d : Lagrange.BasisInput s v i) (hi : i ∈ s) :
Lagrange.classicalNodalWeight s v i d = (Polynomial.eval (v i) (Polynomial.derivative (Lagrange.nodal s v)))⁻¹
Lean proof
/-- At a node the weight is the reciprocal derivative of the nodal polynomial. -/
theorem classicalNodalWeight_eq_derivative {s : Finset ι} {v : ι → F} {i : ι}
(d : BasisInput s v i) (hi : i ∈ s) :
classicalNodalWeight s v i d = ((nodal s v).derivative.eval (v i))⁻¹ :=
nodalWeight_eq_eval_derivative_nodal hi
theorem Lagrange.derivative_nodal_ne_zero.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] {s : Finset ι}
{v : ι → F} {i : ι} (d : Lagrange.BasisInput s v i) (hi : i ∈ s) :
Polynomial.eval (v i) (Polynomial.derivative (Lagrange.nodal s v)) ≠ 0
Lean proof
/-- The derivative denominator in the classical nodal-weight formula is nonzero. -/
theorem derivative_nodal_ne_zero {s : Finset ι} {v : ι → F} {i : ι}
(d : BasisInput s v i) (hi : i ∈ s) : (nodal s v).derivative.eval (v i) ≠ 0 := by
rw [eval_nodal_derivative_eval_node_eq hi]
exact eval_nodal_not_at_node d.separated
theorem Lagrange.eval_classicalBasis_not_at_node.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι]
{s : Finset ι} {v : ι → F} {i : ι} (d : Lagrange.BasisInput s v i) (hi : i ∈ s) (x : { x // x ≠ v i }) :
Polynomial.eval (↑x) (Lagrange.classicalBasis s v i d) =
Polynomial.eval (↑x) (Lagrange.nodal s v) * (Lagrange.classicalNodalWeight s v i d * (↑x - v i)⁻¹)
Lean proof
/-- First barycentric form of a classical cardinal polynomial, off its own node. -/
theorem eval_classicalBasis_not_at_node {s : Finset ι} {v : ι → F} {i : ι}
(d : BasisInput s v i) (hi : i ∈ s) (x : {x : F // x ≠ v i}) :
(classicalBasis s v i d).eval x.val =
(nodal s v).eval x.val * (classicalNodalWeight s v i d * (x.val - v i)⁻¹) :=
eval_basis_not_at_node hi x.property
A finite interpolation configuration consists of a finite index set \(s\) and field-valued nodes \((v_i)_{i\in s}\) with \(v_i\ne v_j\) whenever \(i\ne j\). The set \(s\) may be empty.
Lean Formalisation
inductive Lagrange.InterpolationInput.{u_1, u_2} {F : Type u_1} {ι : Type u_2} (s : Finset ι) (v : ι → F) : Prop
Lean definition
/-- Distinct-node data for classical interpolation, including the empty set. -/
structure InterpolationInput (s : Finset ι) (v : ι → F) : Prop where
distinct : Set.InjOn v s
For a finite interpolation configuration \((s,v)\), every \(i\in s\) satisfies \(v_i-v_j\ne 0\) for \(j\in s\setminus \{ i\} \), so the normalized nodal product \(\ell _i\) is defined.
Lean Formalisation
theorem Lagrange.InterpolationInput.basis.{u_1, u_2} {F : Type u_1} {ι : Type u_2} [DecidableEq ι] {s : Finset ι} {v : ι → F}
(d : Lagrange.InterpolationInput s v) (i : ↥s) : Lagrange.BasisInput s v ↑i
Lean proof
/-- Every interpolation node has a valid classical product. -/
theorem InterpolationInput.basis {s : Finset ι} {v : ι → F}
(d : InterpolationInput s v) (i : s) : BasisInput s v i :=
BasisInput.of_injOn d.distinct i.property
For a finite interpolation configuration \((s,v)\) and values \((r_i)_{i\in s}\), define \(I r=\sum _{i\in s}r_i\ell _i\). For the empty set this is the zero polynomial. Reference: [DLMF, 3.3(i)].
Lean Formalisation
def Lagrange.classicalInterpolate.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (_d : Lagrange.InterpolationInput s v) (r : ι → F) : Polynomial F
Lean definition
/-- Classical interpolation polynomial (DLMF §3.3(i)). -/
noncomputable def classicalInterpolate (s : Finset ι) (v : ι → F)
(_d : InterpolationInput s v) (r : ι → F) : F[X] := interpolate s v r
The interpolant is the displayed cardinal-polynomial sum, attains the data at every node, and has degree less than \(|s|\), with the degree of zero understood as \(-\infty \).
Lean Formalisation
theorem Lagrange.classicalInterpolate_apply.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] (s : Finset ι)
(v : ι → F) (d : Lagrange.InterpolationInput s v) (r : ι → F) :
Lagrange.classicalInterpolate s v d r = ∑ i, Polynomial.C (r ↑i) * Lagrange.classicalBasis s v ↑i ⋯
Lean proof
/-- Expansion in the classical cardinal polynomials. -/
theorem classicalInterpolate_apply (s : Finset ι) (v : ι → F)
(d : InterpolationInput s v) (r : ι → F) :
classicalInterpolate s v d r = ∑ i : s, C (r i) * classicalBasis s v i (d.basis i) := by
exact (Finset.sum_coe_sort s (fun i ↦ C (r i) * Lagrange.basis s v i)).symm
theorem Lagrange.eval_classicalInterpolate.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] {s : Finset ι}
{v : ι → F} (d : Lagrange.InterpolationInput s v) (r : ι → F) (i : ↥s) :
Polynomial.eval (v ↑i) (Lagrange.classicalInterpolate s v d r) = r ↑i
Lean proof
/-- Classical interpolation attains its data. -/
theorem eval_classicalInterpolate {s : Finset ι} {v : ι → F}
(d : InterpolationInput s v) (r : ι → F) (i : s) :
(classicalInterpolate s v d r).eval (v i) = r i :=
eval_interpolate_at_node r d.distinct i.property
A barycentric evaluation configuration consists of a nonempty finite set of distinct nodes and an evaluation point \(z\) different from every node.
Lean Formalisation
inductive Lagrange.BarycentricInput.{u_1, u_2} {F : Type u_1} {ι : Type u_2} (s : Finset ι) (v : ι → F) : Type u_1
Lean definition
/-- Nonempty distinct nodes and an evaluation point off all nodes. -/
structure BarycentricInput (s : Finset ι) (v : ι → F) where
nodes : InterpolationInput s v
nonempty : s.Nonempty
point : {x : F // ∀ i ∈ s, x ≠ v i}
For each node, \(\omega _i\ne 0\) and \(z-v_i\ne 0\).
Lean Formalisation
theorem Lagrange.BarycentricInput.valid.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι] {s : Finset ι}
{v : ι → F} (d : Lagrange.BarycentricInput s v) (i : ↥s) :
Lagrange.classicalNodalWeight s v ↑i ⋯ ≠ 0 ∧ ↑d.point - v ↑i ≠ 0
Lean proof
/-- Both the nodal and point-difference denominators are nonzero. -/
theorem BarycentricInput.valid {s : Finset ι} {v : ι → F}
(d : BarycentricInput s v) (i : s) :
classicalNodalWeight s v i (d.nodes.basis i) ≠ 0 ∧ d.point.val - v i ≠ 0 :=
⟨classicalNodalWeight_ne_zero _ _ _ _, sub_ne_zero.mpr (d.point.property i i.property)⟩
For \(N\ge 1\), put \(x_j=\cos (j\pi /N)\) and \(S_N(g)=\tfrac 12g(0)+\sum _{j=1}^{N-1}g(j)+\tfrac 12g(N)\). For real-valued data and \(0\le k\le N\), define
\[ c_k=\frac{2-\mathbf1_{k=0\text{ or }k=N}}{N} S_N\bigl(j\mapsto f(x_j)T_k(x_j)\bigr),\qquad P_Nf=\sum _{k=0}^N c_kT_k. \]
For \(N=0\), define \(P_0f\) to be the constant polynomial \(f(1)\).
def Polynomial.Chebyshev.extremaSum (N : { n // 0 < n }) (f : ℕ → ℝ) : ℝ
Lean definition
/-- The endpoint-half-weighted sum on the extrema indices `0,...,N`.
This is the usual double-primed sum at positive order. -/
noncomputable def extremaSum (N : {n : ℕ // 0 < n}) (f : ℕ → ℝ) : ℝ :=
(∑ j ∈ Finset.range N.val, f j) + (f N.val - f 0) / 2
For \(N\ge 1\) and \(0\le j,k\le N\), the discrete inner product \(S_N(\ell \mapsto T_j(x_\ell )T_k(x_\ell ))\) vanishes if \(j\ne k\). Its diagonal is \(N\) for \(k=0,N\) and \(N/2\) otherwise. Consequently \(c_k(T_j)=\delta _{jk}\).
theorem Polynomial.Chebyshev.extremaSum_sq_eval_T {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) :
(Polynomial.Chebyshev.extremaSum ⟨N, ⋯⟩ fun m =>
Polynomial.eval (Polynomial.Chebyshev.node N m) (Polynomial.Chebyshev.T ℝ ↑k) ^ 2) =
if k = 0 ∨ k = N then ↑N else ↑N / 2
Lean proof
/-- Endpoint modes have discrete squared norm `N`, and all interior modes `N/2`. -/
theorem extremaSum_sq_eval_T {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) :
extremaSum ⟨N, by omega⟩ (fun m ↦ (T ℝ k).eval (node N m) ^ 2) =
if k = 0 ∨ k = N then (N : ℝ) else N / 2 := by
have h := extremaSum_product (N := N) (j := k) (k := k) (Nat.pos_of_ne_zero hN) le_rfl
simp only [Nat.sub_self, Nat.cast_zero, T_zero, eval_one, extremaSum_one] at h
by_cases hzero : k = 0
· subst k
simp
· by_cases hlast : k = N
· subst k
rw [show N + N = 2 * N by omega, extremaSum_eval_T_two_mul hN] at h
rw [ite_eq_left (Or.inr rfl)]
simpa only [pow_two] using (show extremaSum ⟨N, by omega⟩
(fun m ↦ (T ℝ N).eval (node N m) * (T ℝ N).eval (node N m)) = N by linarith)
· rw [extremaSum_eval_T (by omega : k + k < 2 * N),
ite_eq_right (by omega : k + k ≠ 0)] at h
rw [ite_eq_right (by simp [hzero, hlast])]
simpa only [pow_two] using (show extremaSum ⟨N, by omega⟩
(fun m ↦ (T ℝ k).eval (node N m) * (T ℝ k).eval (node N m)) = (N : ℝ) / 2 by linarith)
For \(N\ge 1\), \(P_Nf\) equals the Lagrange interpolant at the extrema and \(P_Nf(x_j)=f(x_j)\) for \(0\le j\le N\). It reproduces every real polynomial of degree at most \(N\). Its integral-defined Chebyshev coefficient of index \(k\) is \(c_k\) for \(k\le N\) and zero otherwise.
theorem Polynomial.Chebyshev.dctInterpolant_eval {N : ℕ} (hN : N ≠ 0) {p : Polynomial ℝ} (hp : p.degree ≤ ↑N) :
(Polynomial.Chebyshev.dctInterpolant N fun x => Polynomial.eval x p) = p
Lean proof
/-- Resolved polynomial data are reconstructed exactly by the DCT-I. -/
theorem dctInterpolant_eval {N : ℕ} (hN : N ≠ 0) {p : ℝ[X]} (hp : p.degree ≤ N) :
dctInterpolant N (fun x ↦ p.eval x) = p := by
have hm : p ∈ Submodule.span ℝ (chebyshevTsequence ℝ '' Set.Iic N) := by
rw [(chebyshevTsequence ℝ).span_degreeLE
(fun i _ ↦ (chebyshevTsequence ℝ).isUnit_leadingCoeff i), mem_degreeLE]
exact hp
clear hp
induction hm using Submodule.span_induction with
| mem p hp =>
obtain ⟨j, hj, rfl⟩ := hp
change j ≤ N at hj
change dctInterpolant N (fun x ↦ (T ℝ j).eval x) = T ℝ j
simp only [dctInterpolant, dite_eq_right hN]
have he (k : Fin (N + 1)) :=
extremaCoefficient_eval_T hN hj (Nat.le_of_lt_succ k.isLt)
simp_rw [he]
rw [Fin.sum_univ_eq_sum_range (fun k ↦ Polynomial.C (if j = k then (1 : ℝ) else 0) * T ℝ k)]
simp [show j < N + 1 by omega]
| zero => simp [dctInterpolant, extremaCoefficient, extremaSum]
| add p q _ _ hp hq =>
simp only [eval_add, dctInterpolant, dite_eq_right hN, extremaCoefficient_add, map_add,
add_mul, Finset.sum_add_distrib] at hp hq ⊢
rw [hp, hq]
| smul a p _ hp =>
simp only [eval_smul, smul_eq_mul, extremaCoefficient_mul, dctInterpolant, dite_eq_right hN,
map_mul, mul_assoc, ← Finset.mul_sum] at hp ⊢
rw [hp]
exact (smul_eq_C_mul a).symm
theorem Polynomial.Chebyshev.dctInterpolant_eq_lagrange (N : { n // 0 < n }) (f : ℝ → ℝ) :
Polynomial.Chebyshev.dctInterpolant (↑N) f =
Lagrange.classicalInterpolate (Finset.range (↑N + 1)) (Polynomial.Chebyshev.classicalNode N) ⋯ fun j =>
f (Polynomial.Chebyshev.classicalNode N j)
Lean proof
/-- The DCT-I reconstructs classical distinct-node interpolation. -/
theorem dctInterpolant_eq_lagrange (N : {n : ℕ // 0 < n}) (f : ℝ → ℝ) :
dctInterpolant N.val f =
Lagrange.classicalInterpolate (Finset.range (N.val + 1)) (classicalNode N)
⟨(strictAntiOn_classicalNode N).injOn⟩ (fun j ↦ f (classicalNode N j)) := by
rcases N with ⟨N,hNp⟩
have hN := Nat.ne_of_gt hNp
change dctInterpolant N f = Lagrange.interpolate (Finset.range (N+1)) (node N)
(fun j ↦ f (node N j))
let p := Lagrange.interpolate (Finset.range (N + 1)) (node N) (fun j ↦ f (node N j))
have hv := (strictAntiOn_node N).injOn
have hp : p.degree ≤ N := by
have h := Lagrange.degree_interpolate_lt (fun j ↦ f (node N j)) hv
simp only [Finset.card_range] at h
by_cases hz : p = 0
· simp [hz]
· exact degree_le_of_natDegree_le
(Nat.le_of_lt_succ ((natDegree_lt_iff_degree_lt hz).2 h))
have he (j : ℕ) (hj : j ≤ N) : p.eval (node N j) = f (node N j) :=
Lagrange.eval_interpolate_at_node _ hv (Finset.mem_range.mpr (by omega))
change dctInterpolant N f = p
rw [← dctInterpolant_eval hN hp]
simp only [dctInterpolant, dite_eq_right hN]
apply Finset.sum_congr rfl
intro k hk
congr 2
simp only [extremaCoefficient_eq_sum hN]
unfold extremaSum
dsimp only
rw [he N le_rfl, he 0 (Nat.zero_le N)]
congr 2
apply Finset.sum_congr rfl
intro j hj
rw [he j (by simpa using (Finset.mem_range.mp hj).le)]
theorem Polynomial.Chebyshev.coefficient_dctInterpolant (N : ℕ) (f : ℝ → ℝ) (k : ℕ) :
Polynomial.Chebyshev.coefficient ⟨fun x => Polynomial.eval x (Polynomial.Chebyshev.dctInterpolant N f), ⋯⟩ =
if hN : N = 0 then if k = 0 then f 1 else 0
else if hk : k ≤ N then Polynomial.Chebyshev.extremaCoefficient ⟨N, ⋯⟩ f ⟨k, ⋯⟩ else 0
Lean proof
/-- The DCT normalization is exactly the project's weighted-integral coefficient
normalization on the interpolating polynomial, with zero coefficients above `N`. -/
theorem coefficient_dctInterpolant (N : ℕ) (f : ℝ → ℝ) (k : ℕ) :
(coefficient (n := k) ⟨(fun x ↦ (dctInterpolant N f).eval x), by first | assumption | apply integrable_classicalMeasureT; fun_prop⟩) =
if hN : N = 0 then (if k = 0 then f 1 else 0)
else if hk : k ≤ N then
extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩ f ⟨k, Nat.lt_succ_of_le hk⟩ else 0 := by
by_cases hN : N = 0
· subst N
simpa only [dctInterpolant_zero, eval_C, dite_true, coefficient,
CoefficientInput.ofContinuousOn_val] using coefficient_const (f 1) k
simp only [dite_eq_right hN, dctInterpolant, eval_finsetSum, eval_mul, eval_C]
simp only [coefficient, Finset.sum_mul]
rw [MeasureTheory.integral_finsetSum Finset.univ
(fun i _ ↦ integrable_classicalMeasureT (by fun_prop)), Finset.mul_sum]
simp only [mul_assoc, MeasureTheory.integral_const_mul]
have hc (i : Fin (N + 1)) :
(if k = 0 then 1 else 2) / Real.pi *
(extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩ f i *
∫ x, (T ℝ i.val).eval x * (T ℝ k).eval x ∂classicalMeasureT) =
extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩ f i *
(if i.val = k then 1 else 0) := by
rw [← coefficient_eval_T i.val k]
simp only [coefficient, CoefficientInput.ofContinuousOn, CoefficientInput.ofL1]
ring
simp_rw [hc]
by_cases hk : k ≤ N
· rw [dite_eq_left hk, Finset.sum_eq_single (⟨k, Nat.lt_succ_of_le hk⟩ : Fin (N + 1))]
· simp
· intro b _ hb
simp [show b.val ≠ k from fun h ↦ hb (Fin.ext h)]
· simp
· rw [dite_eq_right hk]
apply Finset.sum_eq_zero
intro b _
simp [show b.val ≠ k by have := b.isLt; omega]
This direct implementation evaluates the DCT formula in \(O(N^2)\) operations. Sampling \(T_3\) at six extrema gives its unit coefficient vector in exact arithmetic. The computation uses floating-point values. An FFT-based implementation can be faster; none is implemented here.
functionchebcoeffs(f,N)# c_k of Definition (DCT-I)@assertN>=1x=[cos(j*pi/N)forjin0:N]w=[j==0||j==N?1/2:1.0forjin0:N][(k==0||k==N?1:2)/N*sum(w[j+1]*f(x[j+1])*cos(k*j*pi/N)forjin0:N)forkin0:N]endchebcoeffs(x->4x^3-3x,5)# [0, 0, 0, 1, 0, 0] up to rounding
For positive order the coefficients are the stated half-endpoint cosine sum. For \(N=0\), \(P_0f\) is the constant polynomial \(f(1)\).
Lean Formalisation
theorem Polynomial.Chebyshev.extremaCoefficient_positive (N : { n // 0 < n }) (f : ℝ → ℝ) (k : Fin (↑N + 1)) :
Polynomial.Chebyshev.extremaCoefficient N f k =
(if ↑k = 0 ∨ ↑k = ↑N then 1 else 2) / ↑↑N *
Polynomial.Chebyshev.extremaSum N fun j =>
f (Polynomial.Chebyshev.classicalNode N j) *
Polynomial.eval (Polynomial.Chebyshev.classicalNode N j) (Polynomial.Chebyshev.T ℝ ↑↑k)
Lean proof
/-- Classical positive-order DCT-I formula, in the full-constant convention. -/
theorem extremaCoefficient_positive (N : {n : ℕ // 0 < n}) (f : ℝ → ℝ)
(k : Fin (N.val + 1)) :
extremaCoefficient N f k = (if k.val = 0 ∨ k.val = N.val then 1 else 2) / N.val *
extremaSum N (fun j ↦ f (classicalNode N j) *
(T ℝ k.val).eval (classicalNode N j)) := rfl
/-- Order zero agrees with the constant singleton interpolant. -/
theorem dctInterpolant_zero (f : ℝ → ℝ) : dctInterpolant 0 f = Polynomial.C (f 1) := by
simp [dctInterpolant]
For \(N\ge 1\), fold a frequency \(k\) by setting \(r=k\bmod 2N\) and \(A_N(k)=\min (r,2N-r)\). For \(N=0\), set \(A_0(k)=0\).
Lean Formalisation
def Polynomial.Chebyshev.aliasIndex (N k : ℕ) : ℕ
Lean definition
/-- The degree obtained by folding a frequency into `[0,N]` (ATAP, Chapter 4). -/
def aliasIndex (N k : ℕ) : ℕ :=
if N = 0 then 0 else min (k % (2 * N)) (2 * N - k % (2 * N))
For \(N\ge 1\), set \(r=k\bmod 2N\) and \(m=\min (r,2N-r)\). Then \(0\le m\le N\), \(m=k\) if \(k\le N\), and \(T_k(\cos (j\pi /N))=T_m(\cos (j\pi /N))\) for every nonnegative integer \(j\). At order zero, \(A_0(k)=0\) for every \(k\).
theorem Polynomial.Chebyshev.aliasIndex_le {N : ℕ} (hN : N ≠ 0) (k : ℕ) : Polynomial.Chebyshev.aliasIndex N k ≤ N
Lean proof
/-- A folded frequency has degree at most the interpolation degree. -/
theorem aliasIndex_le {N : ℕ} (hN : N ≠ 0) (k : ℕ) : aliasIndex N k ≤ N := by
have hmod := Nat.mod_lt k (show 0 < 2 * N by omega)
simp only [aliasIndex, ite_eq_right hN]
omega
theorem Polynomial.Chebyshev.aliasIndex_eq_self {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) : Polynomial.Chebyshev.aliasIndex N k = k
Lean proof
/-- Frequencies at or below the interpolation degree are unchanged. -/
theorem aliasIndex_eq_self {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) : aliasIndex N k = k := by
simp only [aliasIndex, ite_eq_right hN]
rw [Nat.mod_eq_of_lt (by omega)]
omega
More generally, if \(\sum _{m\ge 0}a_mT_m(x_j)\) is absolutely summable with sum \(f(x_j)\) at every extremum, then \(\sum _{m\ge 0}\mathbf1_{A_N(m)=k}a_m\) is summable with sum \(c_k(f)\). Summability is unconditional: sums are limits over finite subsets of indices.
theorem Polynomial.Chebyshev.extremaCoefficient_eval_T_alias {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) (m : ℕ) :
Polynomial.Chebyshev.extremaCoefficient ⟨N, ⋯⟩ (fun x => Polynomial.eval x (Polynomial.Chebyshev.T ℝ ↑m)) ⟨k, ⋯⟩ =
if Polynomial.Chebyshev.aliasIndex N m = k then 1 else 0
Lean proof
/-- An arbitrary frequency contributes exactly to its folded DCT coefficient. -/
theorem extremaCoefficient_eval_T_alias {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) (m : ℕ) :
extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩ (fun x ↦ (T ℝ m).eval x)
⟨k, Nat.lt_succ_of_le hk⟩ =
if aliasIndex N m = k then 1 else 0 := by
rw [extremaCoefficient_congr (g := fun x ↦ (T ℝ (aliasIndex N m)).eval x)
(fun j ↦ by simpa only [extremaGridNode_positive ⟨N,Nat.pos_of_ne_zero hN⟩] using
eval_T_node_aliasIndex ⟨N,Nat.pos_of_ne_zero hN⟩ m j)]
exact extremaCoefficient_eval_T hN (aliasIndex_le hN m) hk
theorem Polynomial.Chebyshev.extremaCoefficient_sum_eval_T {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) (s : Finset ℕ) (a : ℕ → ℝ) :
Polynomial.Chebyshev.extremaCoefficient ⟨N, ⋯⟩
(fun x => ∑ m ∈ s, a m * Polynomial.eval x (Polynomial.Chebyshev.T ℝ ↑m)) ⟨k, ⋯⟩ =
∑ m ∈ s, if Polynomial.Chebyshev.aliasIndex N m = k then a m else 0
Lean proof
/-- Coefficient-level aliasing of a finite Chebyshev series (ATAP, Theorem 4.2). -/
theorem extremaCoefficient_sum_eval_T {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N)
(s : Finset ℕ) (a : ℕ → ℝ) :
extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩
(fun x ↦ ∑ m ∈ s, a m * (T ℝ m).eval x) ⟨k, Nat.lt_succ_of_le hk⟩ =
∑ m ∈ s, if aliasIndex N m = k then a m else 0 := by
rw [extremaCoefficient_sum]
simp only [extremaCoefficient_mul, extremaCoefficient_eval_T_alias hN hk,
mul_ite, mul_one, mul_zero]
theorem Polynomial.Chebyshev.hasSum_alias_coefficients {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N) {a : ℕ → ℝ} {f : ℝ → ℝ}
(hf :
∀ (j : Fin (N + 1)),
HasSum (fun m => a m * Polynomial.eval (Polynomial.Chebyshev.extremaGridNode N j) (Polynomial.Chebyshev.T ℝ ↑m))
(f (Polynomial.Chebyshev.extremaGridNode N j))) :
HasSum (fun m => if Polynomial.Chebyshev.aliasIndex N m = k then a m else 0)
(Polynomial.Chebyshev.extremaCoefficient ⟨N, ⋯⟩ f ⟨k, ⋯⟩)
Lean proof
/-- Coefficient aliasing for summable Chebyshev data, grouped by the exact
folding index. The nodal hypotheses use `HasSum` (unconditional convergence);
absolute summability of the source coefficients suffices (ATAP, Theorem 4.2). -/
theorem hasSum_alias_coefficients {N k : ℕ} (hN : N ≠ 0) (hk : k ≤ N)
{a : ℕ → ℝ} {f : ℝ → ℝ}
(hf : ∀ j : Fin (N + 1), HasSum (fun m ↦ a m * (T ℝ m).eval (extremaGridNode N j))
(f (extremaGridNode N j))) :
HasSum (fun m ↦ if aliasIndex N m = k then a m else 0) (extremaCoefficient ⟨N, Nat.pos_of_ne_zero hN⟩ f ⟨k, Nat.lt_succ_of_le hk⟩) := by
have h := hasSum_extremaCoefficient (u := fun m x ↦ a m * (T ℝ m).eval x) (N := ⟨N, Nat.pos_of_ne_zero hN⟩) hf ⟨k, Nat.lt_succ_of_le hk⟩
simpa only [extremaCoefficient_mul, extremaCoefficient_eval_T_alias hN hk,
mul_ite, mul_one, mul_zero] using h
The nodal expansion is \(I_N f(z)=\sum _{j=0}^{N} f(x_{N,j})\ell _{N,j}(z)\) using the finite grid of Definition 2.4.2. Interpolation commutes with any Chebyshev series whose ordinary partial sums converge at each of these finitely many points; absolute convergence is not required. Both identities also hold for \(N=0\), when the only interpolation node is \(x_{0,0}=1\).
Lean Formalisation
theorem Polynomial.Chebyshev.extremaInterpolant_T {N : ℕ} (hN : N ≠ 0) (k : ℕ) :
(Polynomial.Chebyshev.extremaInterpolant N fun t => ↑(Polynomial.eval t (Polynomial.Chebyshev.T ℝ ↑k))) =
Polynomial.Chebyshev.T ℂ ↑(Polynomial.Chebyshev.aliasIndex N k)
Lean proof
/-- Interpolation folds a Chebyshev frequency into `[0,N]` (ATAP, Chapter 4). -/
theorem extremaInterpolant_T {N : ℕ} (hN : N ≠ 0) (k : ℕ) :
extremaInterpolant N (fun t : ℝ ↦ (((T ℝ k).eval t : ℝ) : ℂ)) = T ℂ (aliasIndex N k) := by
symm
rw [extremaInterpolant_positive ⟨N,Nat.pos_of_ne_zero hN⟩]
apply Lagrange.eq_interpolate_of_eval_eq _
(Complex.ofReal_injective.comp_injOn (strictAntiOn_classicalNode ⟨N,Nat.pos_of_ne_zero hN⟩).injOn)
· simp only [degree_T, Int.natAbs_natCast, Finset.card_range]
exact_mod_cast (Nat.lt_succ_of_le (aliasIndex_le hN k))
· intro j hj
dsimp only [Function.comp_def]
rw [← complex_ofReal_eval_T]
exact congrArg Complex.ofReal
(eval_T_node_aliasIndex ⟨N,Nat.pos_of_ne_zero hN⟩ k j).symm
theorem Polynomial.Chebyshev.eval_extremaInterpolant (N : ℕ) (f : ℝ → ℂ) (z : ℂ) :
Polynomial.eval z (Polynomial.Chebyshev.extremaInterpolant N f) =
∑ j, f (Polynomial.Chebyshev.extremaGridNode N j) * Polynomial.eval z (Polynomial.Chebyshev.extremaCardinal N j)
Lean proof
/-- Evaluation as a finite sum of classical cardinal polynomials. -/
theorem eval_extremaInterpolant (N : ℕ) (f : ℝ → ℂ) (z : ℂ) :
(extremaInterpolant N f).eval z = ∑ j : Fin (N + 1),
f (extremaGridNode N j) * (extremaCardinal N j).eval z := by
by_cases hN : N = 0
· subst N
simp [extremaInterpolant_zero, extremaCardinal_zero, extremaGridNode_zero]
· rw [extremaInterpolant_positive ⟨N,Nat.pos_of_ne_zero hN⟩]
simp only [extremaGridNode_positive ⟨N,Nat.pos_of_ne_zero hN⟩,
extremaCardinal_positive ⟨N,Nat.pos_of_ne_zero hN⟩,
Lagrange.classicalInterpolate, Lagrange.classicalBasis,
Lagrange.interpolate_apply, Polynomial.eval_finsetSum,
Polynomial.eval_mul, Polynomial.eval_C]
exact (Fin.sum_univ_eq_sum_range (fun j : ℕ ↦
f (classicalNode ⟨N,Nat.pos_of_ne_zero hN⟩ j) *
(Lagrange.basis (Finset.range (N+1))
(fun k ↦ (classicalNode ⟨N,Nat.pos_of_ne_zero hN⟩ k : ℂ)) j).eval z) (N+1)).symm
theorem Polynomial.Chebyshev.hasSum_eval_extremaInterpolant {N : ℕ} {a : ℕ → ℂ} {f : ℝ → ℂ}
(hs :
∀ (j : Fin (N + 1)),
HasSum
(fun k => a k * ↑(Polynomial.eval (Polynomial.Chebyshev.extremaGridNode N j) (Polynomial.Chebyshev.T ℝ ↑k)))
(f (Polynomial.Chebyshev.extremaGridNode N j)))
(z : ℂ) :
HasSum
(fun k =>
a k *
Polynomial.eval z
(Polynomial.Chebyshev.extremaInterpolant N fun t => ↑(Polynomial.eval t (Polynomial.Chebyshev.T ℝ ↑k))))
(Polynomial.eval z (Polynomial.Chebyshev.extremaInterpolant N f))
Lean proof
/-- Interpolation commutes with an unconditionally convergent series at each node. -/
theorem hasSum_eval_extremaInterpolant {N : ℕ} {a : ℕ → ℂ} {f : ℝ → ℂ}
(hs : ∀ j : Fin (N + 1), HasSum (fun k : ℕ ↦ a k * (((T ℝ k).eval (extremaGridNode N j) : ℝ) : ℂ))
(f (extremaGridNode N j))) (z : ℂ) :
HasSum (fun k : ℕ ↦ a k *
(extremaInterpolant N (fun t : ℝ ↦ (((T ℝ k).eval t : ℝ) : ℂ))).eval z)
((extremaInterpolant N f).eval z) := by
simp_rw [eval_extremaInterpolant, Finset.mul_sum, ← mul_assoc]
exact hasSum_sum fun j hj ↦ (hs j).mul_right _
theorem Polynomial.Chebyshev.tendsto_sum_eval_extremaInterpolant {N : ℕ} {a : ℕ → ℂ} {f : ℝ → ℂ}
(hs :
∀ (j : Fin (N + 1)),
Filter.Tendsto
(fun m =>
∑ k ∈ Finset.range m,
a k * ↑(Polynomial.eval (Polynomial.Chebyshev.extremaGridNode N j) (Polynomial.Chebyshev.T ℝ ↑k)))
Filter.atTop (nhds (f (Polynomial.Chebyshev.extremaGridNode N j))))
(z : ℂ) :
Filter.Tendsto
(fun m =>
∑ k ∈ Finset.range m,
a k *
Polynomial.eval z
(Polynomial.Chebyshev.extremaInterpolant N fun t => ↑(Polynomial.eval t (Polynomial.Chebyshev.T ℝ ↑k))))
Filter.atTop (nhds (Polynomial.eval z (Polynomial.Chebyshev.extremaInterpolant N f)))
Lean proof
/-- Interpolation commutes with ordinary partial-sum limits at its finitely many
nodes; absolute convergence is not required (ATAP, Chapters 4 and 8). -/
theorem tendsto_sum_eval_extremaInterpolant {N : ℕ} {a : ℕ → ℂ} {f : ℝ → ℂ}
(hs : ∀ j : Fin (N + 1), Filter.Tendsto
(fun m : ℕ ↦ ∑ k ∈ Finset.range m,
a k * (((T ℝ k).eval (extremaGridNode N j) : ℝ) : ℂ))
Filter.atTop (nhds (f (extremaGridNode N j)))) (z : ℂ) :
Filter.Tendsto
(fun m : ℕ ↦ ∑ k ∈ Finset.range m, a k *
(extremaInterpolant N (fun t : ℝ ↦ (((T ℝ k).eval t : ℝ) : ℂ))).eval z)
Filter.atTop (nhds ((extremaInterpolant N f).eval z)) := by
simp_rw [eval_extremaInterpolant, Finset.mul_sum, ← mul_assoc]
simp_rw [Finset.sum_comm (s := Finset.range _), ← Finset.sum_mul]
exact tendsto_finsetSum _ fun j _ ↦ (hs j).mul_const _
The barycentric formula evaluates the interpolant directly from its samples. Its weights are \((-1)^j\), halved at the endpoints. At a node, use the prescribed sample value.
Definition
2.4.32Extrema nodal polynomial and weights
For \(N\ge 1\) and \(0\le j\le N\), write \(x_j=\cos (j\pi /N)\) for the extrema nodes. Set \(F_N=(X^2-1)T_N'\), and let \(e_j=2\) for \(j=0\) or \(j=N\), and \(e_j=1\) otherwise. The normalised barycentric weights are \(w_j=(-1)^j/e_j\).
The denominator is nonzero. At a node the interpolant takes its prescribed value. The order-zero interpolant is the constant \(f(1)\). The product weights equal \(\operatorname {lc}(F_N)w_j/N^2\), with a nonzero common factor. For real \(x\ne x_j\), the cardinal polynomial satisfies
theorem Polynomial.Chebyshev.extremaBarycentric_denominator_ne_zero (N : { n // 0 < n })
(z : { z // ∀ j ≤ ↑N, z ≠ ↑(Polynomial.Chebyshev.classicalNode N j) }) :
∑ j, ↑(Polynomial.Chebyshev.extremaBarycentricWeight N j) / (↑z - ↑(Polynomial.Chebyshev.classicalNode N ↑j)) ≠ 0
Lean proof
/-- Nonvanishing on the classical off-grid domain (ATAP, Chapter 5). -/
theorem extremaBarycentric_denominator_ne_zero (N : {n : ℕ // 0 < n})
(z : {z : ℂ // ∀ j ≤ N.val, z ≠ (classicalNode N j : ℂ)}) :
(∑ j : Fin (N.val + 1), (extremaBarycentricWeight N j : ℂ) /
(z.val - (classicalNode N j : ℂ))) ≠ 0 := by
rcases N with ⟨N,hNp⟩
have hN := Nat.ne_of_gt hNp
rcases z with ⟨z,hz⟩
change ∀ j ≤ N, z ≠ (node N j : ℂ) at hz
have hv : Set.InjOn (fun j ↦ (node N j : ℂ)) (Finset.range (N+1)) :=
Complex.ofReal_injective.comp_injOn (strictAntiOn_classicalNode ⟨N,hNp⟩).injOn
change (∑ j : Fin (N + 1), (extremaBarycentricWeight ⟨N, by omega⟩ j : ℂ) /
(z - (node N j : ℂ))) ≠ 0
have h := Lagrange.sum_nodalWeight_mul_inv_sub_ne_zero hv
(fun j hj ↦ hz j (by simpa using hj)) (Finset.nonempty_range_iff.mpr (by omega))
have he : (∑ j ∈ Finset.range (N + 1),
Lagrange.nodalWeight (Finset.range (N + 1)) (fun i ↦ (node N i : ℂ)) j *
(z - (node N j : ℂ))⁻¹) =
(((extremaNodal ⟨N, by omega⟩).leadingCoeff / (N : ℝ) ^ 2 : ℝ) : ℂ) *
∑ j : Fin (N + 1), (extremaBarycentricWeight ⟨N, by omega⟩ j : ℂ) /
(z - (node N j : ℂ)) := by
rw [Finset.mul_sum, ← Fin.sum_univ_eq_sum_range]
apply Finset.sum_congr rfl
intro j _
have hw := nodalWeight_complex_extrema ⟨N,hNp⟩ j
change Lagrange.nodalWeight (Finset.range (N+1)) (fun i ↦ (node N i : ℂ)) j = _ at hw
rw [hw]
simp only [div_eq_mul_inv, mul_assoc]
rw [he] at h
exact (mul_ne_zero_iff.mp h).2
The sum of the absolute cardinal values measures sensitivity to perturbations in the samples. Its maximum over the interval also controls the error relative to a polynomial competitor.
Define \(\lambda _N(x)=\sum _{j=0}^N|\ell _{N,j}(x)|\) using the classical finite-grid cardinal polynomials, for every real \(x\) and \(N\ge 0\). Reference: [ATAP, Chapter 15].
For arbitrary \(f:\mathbb R\to \mathbb C\) and any complex polynomial \(p\) of degree at most \(N\), suppose \(|f(x)-p(x)|\le \varepsilon \) throughout \([-1,1]\). Then, on the same interval,
theorem Polynomial.Chebyshev.extremaInterpolant_sub (N : ℕ) (f g : ℝ → ℂ) :
(Polynomial.Chebyshev.extremaInterpolant N fun x => f x - g x) =
Polynomial.Chebyshev.extremaInterpolant N f - Polynomial.Chebyshev.extremaInterpolant N g
Lean proof
/-- Interpolation commutes with subtraction (ATAP, Chapter 4). -/
theorem extremaInterpolant_sub (N : ℕ) (f g : ℝ → ℂ) :
extremaInterpolant N (fun x ↦ f x - g x) =
extremaInterpolant N f - extremaInterpolant N g := by
by_cases h : N = 0
· subst N
simp only [extremaInterpolant_zero, map_sub]
· simp only [extremaInterpolant_positive ⟨N,Nat.pos_of_ne_zero h⟩,
Lagrange.classicalInterpolate]
exact map_sub (Lagrange.interpolate (Finset.range (N+1))
(fun j ↦ (classicalNode ⟨N,Nat.pos_of_ne_zero h⟩ j : ℂ))) _ _
For a nonempty set \(S\subseteq \mathbb {R}\) that is bounded above, define \(\sup S\) to be its least upper bound in \(\mathbb {R}\).
Lean Formalisation
inductive Real.SupremumInput : Type
Lean definition
/-- The classical domain of a finite real supremum. -/
structure SupremumInput where
carrier : Set ℝ
nonempty : carrier.Nonempty
bounded : BddAbove carrier
For a nonempty set \(S\subseteq \mathbb {R}\) that is bounded above, \(x\le \sup S\) for every \(x\in S\). If \(x\le b\) for every \(x\in S\), then \(\sup S\le b\).
The function equals the displayed finite sum, is nonnegative, and \(\lambda _0(x)=1\). For \(x\in [-1,1]\), \(\lambda _N(x)\le 2\pi +2H_N\); in particular its range on that interval is bounded above. Reference: [ATAP, Chapter 15], with nonsharp constants.
Lean Formalisation
theorem Polynomial.Chebyshev.extremaLebesgueFunction_apply (N : ℕ) (x : ℝ) :
Polynomial.Chebyshev.extremaLebesgueFunction N x =
∑ j, ‖Polynomial.eval (↑x) (Polynomial.Chebyshev.extremaCardinal N j)‖
Lean proof
/-- Classical finite-cardinal-sum formula (ATAP Chapter 15). -/
theorem extremaLebesgueFunction_apply (N : ℕ) (x : ℝ) :
extremaLebesgueFunction N x = ∑ j : Fin (N + 1),
‖(extremaCardinal N j).eval (x : ℂ)‖ := rfl
/-- The order-zero Lebesgue function is one (ATAP, Chapter 15). -/
@[simp] theorem extremaLebesgueFunction_zero (x : ℝ) : extremaLebesgueFunction 0 x = 1 := by
simp [extremaLebesgueFunction, extremaCardinal_zero]
The set \(\{ \lambda _N(x):x\in [-1,1]\} \) is nonempty and bounded above. The constant \(\Lambda _N\) is the least upper bound of \(\{ \lambda _N(x):x\in [-1,1]\} \).
theorem Lagrange.classicalBarycentric_denominator_ne_zero.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι]
{s : Finset ι} {v : ι → F} (d : Lagrange.BarycentricInput s v) :
∑ i, Lagrange.classicalNodalWeight s v ↑i ⋯ * (↑d.point - v ↑i)⁻¹ ≠ 0
Lean proof
/-- The barycentric denominator cannot vanish on the classical input domain. -/
theorem classicalBarycentric_denominator_ne_zero {s : Finset ι} {v : ι → F}
(d : BarycentricInput s v) :
(∑ i : s, classicalNodalWeight s v i (d.nodes.basis i) *
(d.point.val - v i)⁻¹) ≠ 0 := by
change (∑ i : s, nodalWeight s v i * (d.point.val - v i)⁻¹) ≠ 0
rw [Finset.sum_coe_sort s (fun i ↦ nodalWeight s v i * (d.point.val - v i)⁻¹)]
exact sum_nodalWeight_mul_inv_sub_ne_zero d.nodes.distinct d.point.property d.nonempty
theorem Lagrange.eval_classicalInterpolate_barycentric.{u_1, u_2} {F : Type u_1} [Field F] {ι : Type u_2} [DecidableEq ι]
{s : Finset ι} {v : ι → F} (d : Lagrange.BarycentricInput s v) (r : ι → F) :
Polynomial.eval (↑d.point) (Lagrange.classicalInterpolate s v ⋯ r) =
(∑ i, Lagrange.classicalNodalWeight s v ↑i ⋯ * (↑d.point - v ↑i)⁻¹ * r ↑i) /
∑ i, Lagrange.classicalNodalWeight s v ↑i ⋯ * (↑d.point - v ↑i)⁻¹
Lean proof
/-- Second barycentric formula on its full classical domain (ATAP Theorem 5.1). -/
theorem eval_classicalInterpolate_barycentric {s : Finset ι} {v : ι → F}
(d : BarycentricInput s v) (r : ι → F) :
(classicalInterpolate s v d.nodes r).eval d.point.val =
(∑ i : s, classicalNodalWeight s v i (d.nodes.basis i) *
(d.point.val - v i)⁻¹ * r i) /
(∑ i : s, classicalNodalWeight s v i (d.nodes.basis i) *
(d.point.val - v i)⁻¹) := by
change (interpolate s v r).eval d.point.val =
(∑ i : s, nodalWeight s v i * (d.point.val - v i)⁻¹ * r i) /
(∑ i : s, nodalWeight s v i * (d.point.val - v i)⁻¹)
rw [Finset.sum_coe_sort s (fun i ↦ nodalWeight s v i * (d.point.val - v i)⁻¹ * r i),
Finset.sum_coe_sort s (fun i ↦ nodalWeight s v i * (d.point.val - v i)⁻¹)]
exact eval_interpolate_not_at_node' r d.nodes.distinct d.nonempty d.point.property
/-- The nodal polynomial is nonzero for positive order (ATAP, Chapter 5). -/
theorem extremaNodal_ne_zero {N : ℕ} (hN : N ≠ 0) : extremaNodal ⟨N, by omega⟩ ≠ 0 := by
intro h
have hd := eval_derivative_extremaNodal_node hN (j := 0) (Nat.zero_le N)
simp [h, extremaEndpointFactor, hN] at hd
theorem harmonic_le_one_add_log_of_pos (n : { n // 0 < n }) : ↑(harmonic ↑n) ≤ 1 + Real.log ↑↑n
Lean proof
/-- The harmonic logarithmic bound at a positive natural index (ATAP, Chapter 15).
The index type excludes evaluation of the logarithm at zero. -/
theorem harmonic_le_one_add_log_of_pos (n : {n : ℕ // 0 < n}) :
(harmonic n.val : ℝ) ≤ 1 + Real.log n.val :=
harmonic_le_one_add_log n.val