4.2 Banded multiplication, differentiation and conversion
In Jacobi and ultraspherical bases, multiplication by \(x\) is tridiagonal. Differentiation raises the parameters and has a single superdiagonal. One-step conversion has bandwidth \((0,1)\) for Jacobi and \((0,2)\) for ultraspherical bases. These sparse matrices are those of the ultraspherical spectral method [OT13], used by ApproxFun [AF]. The identities with denominators cleared hold over every commutative \(\mathbb {Q}\)-algebra. Divided entries and bandwidths require nonvanishing denominators; these conditions hold in the real orthogonality ranges.
Column zero has entries \(2/(s+2)\) in row one and \((\beta -\alpha )/(s+2)\) in row zero. The divided formulas hold over fields with a rational algebra structure when the displayed denominator factors are nonzero; cleared identities hold over commutative rational algebras. For real \(\alpha ,\beta {\gt}-1\) all factors are nonzero and the matrix has bandwidths \((1,1)\).
theorem Polynomial.jacobi_mul_matrix_zero.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (α β : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.jacobi α β k) (i : ℕ) :
(α + β + 2) * b.toMatrix (fun j => Polynomial.X * Polynomial.jacobi α β j) i 0 =
(if i = 1 then 2 else 0) + if i = 0 then β - α else 0
Lean proof
/-- The initial multiplication column, without a spurious parameter singularity
(DLMF 18.9.1--2). -/
theorem jacobi_mul_matrix_zero
(hb : ∀ k, b k = jacobi α β k) (i : ℕ) :
(α + β + 2) * b.toMatrix (fun j ↦ X * jacobi α β j) i 0 =
(if i = 1 then 2 else 0) + (if i = 0 then β - α else 0) := by
have he : C (α + β + 2) * (X * jacobi α β 0) =
C 2 * jacobi α β 1 + C (β - α) * jacobi α β 0 := by
rw [jacobi_zero, jacobi_one]
have hhalf : (2 : R) * algebraMap ℚ R (1 / 2) = 1 := by
have hm := congrArg (algebraMap ℚ R) (show (2 : ℚ) * (1 / 2) = 1 by norm_num)
simpa only [map_mul, map_ofNat, map_one] using hm
simp only [map_add, map_sub, map_mul, map_ofNat, map_one]
have hh := congrArg (C : R →+* R[X]) hhalf
simp only [map_mul, map_ofNat, map_one] at hh
linear_combination -(C α + C β + 2) * (X - 1) * hh
have h := congrArg (fun p : R[X] ↦ b.repr p i) he
simp only [← smul_eq_C_mul] at h
simp [Basis.toMatrix_apply, ← hb, Finsupp.single_apply, eq_comm] at h ⊢
split_ifs at h ⊢ <;> first | omega | linear_combination h
theorem Polynomial.jacobi_mul_matrix_succ_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi a b k) (n i : ℕ)
(h2 : 2 * ↑n + a + b + 2 ≠ 0) (h3 : 2 * ↑n + a + b + 3 ≠ 0) (h4 : 2 * ↑n + a + b + 4 ≠ 0) :
B.toMatrix (fun j => Polynomial.X * Polynomial.jacobi a b j) i (n + 1) =
((if i = n + 2 then 2 * (↑n + 2) * (↑n + a + b + 2) / ((2 * ↑n + a + b + 3) * (2 * ↑n + a + b + 4)) else 0) +
if i = n + 1 then (b ^ 2 - a ^ 2) / ((2 * ↑n + a + b + 2) * (2 * ↑n + a + b + 4)) else 0) +
if i = n then 2 * (↑n + a + 1) * (↑n + b + 1) / ((2 * ↑n + a + b + 2) * (2 * ↑n + a + b + 3)) else 0
Lean proof
/-- The standard three rational multiplication entries (DLMF 18.9.2_2,
with positive input degree). -/
theorem jacobi_mul_matrix_succ_div (hB : ∀ k, B k = jacobi a b k) (n i : ℕ)
(h2 : 2 * (n : K) + a + b + 2 ≠ 0)
(h3 : 2 * (n : K) + a + b + 3 ≠ 0)
(h4 : 2 * (n : K) + a + b + 4 ≠ 0) :
B.toMatrix (fun j ↦ X * jacobi a b j) i (n + 1) =
(if i = n + 2 then 2 * (n + 2) * (n + a + b + 2) /
((2 * n + a + b + 3) * (2 * n + a + b + 4)) else 0) +
(if i = n + 1 then (b ^ 2 - a ^ 2) /
((2 * n + a + b + 2) * (2 * n + a + b + 4)) else 0) +
(if i = n then 2 * (n + a + 1) * (n + b + 1) /
((2 * n + a + b + 2) * (2 * n + a + b + 3)) else 0) := by
apply mul_left_cancel₀ (mul_ne_zero (mul_ne_zero h3 h2) h4)
rw [jacobi_mul_matrix_succ a b B hB n i]
split_ifs <;> field_simp <;> ring
theorem Polynomial.jacobi_mul_matrix_zero_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi a b k) (i : ℕ) (hd : a + b + 2 ≠ 0) :
B.toMatrix (fun j => Polynomial.X * Polynomial.jacobi a b j) i 0 =
((if i = 1 then 2 else 0) + if i = 0 then b - a else 0) / (a + b + 2)
Lean proof
/-- The divided initial multiplication column (DLMF 18.9.2_2). -/
theorem jacobi_mul_matrix_zero_div (hB : ∀ k, B k = jacobi a b k) (i : ℕ)
(hd : a + b + 2 ≠ 0) :
B.toMatrix (fun j ↦ X * jacobi a b j) i 0 =
((if i = 1 then 2 else 0) + (if i = 0 then b - a else 0)) / (a + b + 2) := by
apply (eq_div_iff hd).2
simpa only [mul_comm] using jacobi_mul_matrix_zero a b B hB i
theorem Polynomial.jacobi_mul_matrix_isBanded.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi a b k) (hzero : a + b + 2 ≠ 0)
(hd : ∀ (n : ℕ), (2 * ↑n + a + b + 3) * (2 * ↑n + a + b + 2) * (2 * ↑n + a + b + 4) ≠ 0) :
(B.toMatrix fun j => Polynomial.X * Polynomial.jacobi a b j).IsBanded 1 1
Lean proof
/-- Jacobi multiplication is tridiagonal when the recurrence factors can be
cancelled (DLMF 18.9.1--2; Olver--Townsend 2013). -/
theorem jacobi_mul_matrix_isBanded (hB : ∀ k, B k = jacobi a b k)
(hzero : a + b + 2 ≠ 0)
(hd : ∀ n : ℕ, (2 * (n : K) + a + b + 3) *
(2 * n + a + b + 2) * (2 * n + a + b + 4) ≠ 0) :
(B.toMatrix (fun j ↦ X * jacobi a b j)).IsBanded 1 1 := by
intro i j hij
cases j with
| zero =>
have h := jacobi_mul_matrix_zero a b B hB i
simp only [ite_eq_right (show i ≠ 1 by omega),
ite_eq_right (show i ≠ 0 by omega), zero_add] at h
exact (mul_eq_zero.mp h).resolve_left hzero
| succ n =>
have h := jacobi_mul_matrix_succ a b B hB n i
simp only [ite_eq_right (show i ≠ n + 2 by omega),
ite_eq_right (show i ≠ n + 1 by omega), ite_eq_right (show i ≠ n by omega),
sub_self, add_zero] at h
exact (mul_eq_zero.mp h).resolve_left (hd n)
Jacobi differentiation from \((\alpha ,\beta )\) to \((\alpha +1,\beta +1)\) has entry \((n+\alpha +\beta +2)/2\) in row \(n\), column \(n+1\). Gegenbauer differentiation from \(\lambda \) to \(\lambda +1\) has entry \(2\lambda \) in row \(n\), column \(n+1\). All other entries vanish, including column zero. These are identities over commutative rational algebras whenever the specified target bases exist; both matrices have bandwidths \((0,1)\). The concrete real bases above supply them throughout their orthogonality ranges.
theorem Polynomial.gegenbauer_derivative_matrix_succ.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer (lam + 1) k) (n i : ℕ) :
b.toMatrix (fun j => Polynomial.derivative (Polynomial.gegenbauer lam j)) i (n + 1) = if i = n then 2 * lam else 0
Lean proof
/-- The derivative matrix in the next Gegenbauer basis has one diagonal
(DLMF 18.9.19). -/
theorem gegenbauer_derivative_matrix_succ
(hb : ∀ k, b k = gegenbauer (lam + 1) k) (n i : ℕ) :
b.toMatrix (fun j ↦ derivative (gegenbauer lam j)) i (n + 1) =
if i = n then 2 * lam else 0 := by
rw [Basis.toMatrix_apply, derivative_gegenbauer_succ, ← smul_eq_C_mul, ← hb]
simp [Finsupp.single_apply, eq_comm]
theorem Polynomial.gegenbauer_derivative_matrix_isBanded.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer (lam + 1) k) :
(b.toMatrix fun j => Polynomial.derivative (Polynomial.gegenbauer lam j)).IsBanded 0 1
Lean proof
/-- Differentiation has lower bandwidth zero and upper bandwidth one
(DLMF 18.9.19; Olver--Townsend 2013). -/
theorem gegenbauer_derivative_matrix_isBanded
(hb : ∀ k, b k = gegenbauer (lam + 1) k) :
(b.toMatrix (fun j ↦ derivative (gegenbauer lam j))).IsBanded 0 1 := by
intro i j hij
cases j with
| zero => exact gegenbauer_derivative_matrix_zero lam b i
| succ n =>
rw [gegenbauer_derivative_matrix_succ lam b hb]
exact ite_eq_right (by omega)
Let \(s=\alpha +\beta \). For input degree \(n\ge 1\), conversion raising \(\alpha \) has entries \((n+s+1)/(2n+s+1)\) in row \(n\) and \(-(n+\beta )/(2n+s+1)\) in row \(n-1\). Conversion raising \(\beta \) has the same diagonal entry and \((n+\alpha )/(2n+s+1)\) in row \(n-1\). Column zero is the unit column at zero. All other entries vanish. The divided formulas require \(2n+s+1\ne 0\) over a field; the cleared identities hold over every commutative rational algebra with the specified target basis. For real \(\alpha ,\beta {\gt}-1\) both matrices have bandwidths \((0,1)\) with no additional denominator hypotheses.
theorem Polynomial.jacobi_raise_beta_matrix_succ.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (α β : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.jacobi α (β + 1) k) (n i : ℕ) :
(2 * ↑n + α + β + 3) * b.toMatrix (Polynomial.jacobi α β) i (n + 1) =
(if i = n + 1 then ↑n + α + β + 2 else 0) + if i = n then ↑n + α + 1 else 0
Lean proof
/-- Cleared entries for raising the second parameter (DLMF 18.9.5). -/
theorem jacobi_raise_beta_matrix_succ
(hb : ∀ k, b k = jacobi α (β + 1) k) (n i : ℕ) :
(2 * n + α + β + 3) * b.toMatrix (jacobi α β) i (n + 1) =
(if i = n + 1 then n + α + β + 2 else 0) +
(if i = n then n + α + 1 else 0) := by
have h := congrArg (fun p : R[X] ↦ b.repr p i) (jacobi_raise_beta α β n)
simp only [← smul_eq_C_mul] at h
simp only [map_add, map_smul, Finsupp.coe_add, Pi.add_apply,
Finsupp.coe_smul, Pi.smul_apply, smul_eq_mul, ← hb] at h
simpa [Basis.toMatrix_apply, Finsupp.single_apply, eq_comm, mul_ite] using h
theorem Polynomial.jacobi_raise_alpha_matrix_succ.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (α β : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.jacobi (α + 1) β k) (n i : ℕ) :
(2 * ↑n + α + β + 3) * b.toMatrix (Polynomial.jacobi α β) i (n + 1) =
(if i = n + 1 then ↑n + α + β + 2 else 0) - if i = n then ↑n + β + 1 else 0
Lean proof
/-- Cleared entries for raising the first parameter (DLMF 18.9.5 by reflection). -/
theorem jacobi_raise_alpha_matrix_succ
(hb : ∀ k, b k = jacobi (α + 1) β k) (n i : ℕ) :
(2 * n + α + β + 3) * b.toMatrix (jacobi α β) i (n + 1) =
(if i = n + 1 then n + α + β + 2 else 0) -
(if i = n then n + β + 1 else 0) := by
have h := congrArg (fun p : R[X] ↦ b.repr p i) (jacobi_raise_alpha α β n)
simp only [← smul_eq_C_mul] at h
simp only [map_sub, map_smul, Finsupp.coe_sub, Pi.sub_apply,
Finsupp.coe_smul, Pi.smul_apply, smul_eq_mul, ← hb] at h
simpa [Basis.toMatrix_apply, Finsupp.single_apply, eq_comm, mul_ite] using h
theorem Polynomial.jacobi_conversion_matrix_zero.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (α β : R)
(b : Module.Basis ℕ R (Polynomial R)) {α' β' : R} (hb : ∀ (k : ℕ), b k = Polynomial.jacobi α' β' k) (i : ℕ) :
b.toMatrix (Polynomial.jacobi α β) i 0 = if i = 0 then 1 else 0
Lean proof
/-- Parameter conversion preserves the constant column (DLMF 18.9.5). -/
theorem jacobi_conversion_matrix_zero {α' β' : R}
(hb : ∀ k, b k = jacobi α' β' k) (i : ℕ) :
b.toMatrix (jacobi α β) i 0 = if i = 0 then 1 else 0 := by
have hb0 : b 0 = 1 := by rw [hb, jacobi_zero]
simp [Basis.toMatrix_apply, ← hb0, Finsupp.single_apply, eq_comm]
theorem Polynomial.jacobi_raise_beta_matrix_succ_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi a (b + 1) k) (n i : ℕ)
(hd : 2 * ↑n + a + b + 3 ≠ 0) :
B.toMatrix (Polynomial.jacobi a b) i (n + 1) =
((if i = n + 1 then ↑n + a + b + 2 else 0) + if i = n then ↑n + a + 1 else 0) / (2 * ↑n + a + b + 3)
Lean proof
/-- Divided entries of the upper-bidiagonal second-parameter conversion
(DLMF 18.9.5). The denominator hypothesis is explicit. -/
theorem jacobi_raise_beta_matrix_succ_div
(hB : ∀ k, B k = jacobi a (b + 1) k) (n i : ℕ)
(hd : 2 * (n : K) + a + b + 3 ≠ 0) :
B.toMatrix (jacobi a b) i (n + 1) =
((if i = n + 1 then n + a + b + 2 else 0) +
(if i = n then n + a + 1 else 0)) / (2 * n + a + b + 3) := by
apply (eq_div_iff hd).2
simpa only [mul_comm] using jacobi_raise_beta_matrix_succ a b B hB n i
theorem Polynomial.jacobi_raise_alpha_matrix_succ_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi (a + 1) b k) (n i : ℕ)
(hd : 2 * ↑n + a + b + 3 ≠ 0) :
B.toMatrix (Polynomial.jacobi a b) i (n + 1) =
((if i = n + 1 then ↑n + a + b + 2 else 0) - if i = n then ↑n + b + 1 else 0) / (2 * ↑n + a + b + 3)
Lean proof
/-- Divided entries of the upper-bidiagonal first-parameter conversion
(DLMF 18.9.5 by reflection). -/
theorem jacobi_raise_alpha_matrix_succ_div
(hB : ∀ k, B k = jacobi (a + 1) b k) (n i : ℕ)
(hd : 2 * (n : K) + a + b + 3 ≠ 0) :
B.toMatrix (jacobi a b) i (n + 1) =
((if i = n + 1 then n + a + b + 2 else 0) -
(if i = n then n + b + 1 else 0)) / (2 * n + a + b + 3) := by
apply (eq_div_iff hd).2
simpa only [mul_comm] using jacobi_raise_alpha_matrix_succ a b B hB n i
theorem Polynomial.jacobi_raise_beta_matrix_isBanded.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi a (b + 1) k)
(hd : ∀ (n : ℕ), 2 * ↑n + a + b + 3 ≠ 0) : (B.toMatrix (Polynomial.jacobi a b)).IsBanded 0 1
Lean proof
/-- Raising the second parameter is upper bidiagonal (DLMF 18.9.5). -/
theorem jacobi_raise_beta_matrix_isBanded
(hB : ∀ k, B k = jacobi a (b + 1) k)
(hd : ∀ n : ℕ, 2 * (n : K) + a + b + 3 ≠ 0) :
(B.toMatrix (jacobi a b)).IsBanded 0 1 := by
intro i j hij
cases j with
| zero =>
rw [jacobi_conversion_matrix_zero a b B hB]
exact ite_eq_right (by omega)
| succ n =>
rw [jacobi_raise_beta_matrix_succ_div a b B hB n i (hd n)]
simp [show i ≠ n + 1 by omega, show i ≠ n by omega]
theorem Polynomial.jacobi_raise_alpha_matrix_isBanded.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (a b : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.jacobi (a + 1) b k)
(hd : ∀ (n : ℕ), 2 * ↑n + a + b + 3 ≠ 0) : (B.toMatrix (Polynomial.jacobi a b)).IsBanded 0 1
Lean proof
/-- Raising the first parameter is upper bidiagonal (DLMF 18.9.5 by reflection). -/
theorem jacobi_raise_alpha_matrix_isBanded
(hB : ∀ k, B k = jacobi (a + 1) b k)
(hd : ∀ n : ℕ, 2 * (n : K) + a + b + 3 ≠ 0) :
(B.toMatrix (jacobi a b)).IsBanded 0 1 := by
intro i j hij
cases j with
| zero =>
rw [jacobi_conversion_matrix_zero a b B hB]
exact ite_eq_right (by omega)
| succ n =>
rw [jacobi_raise_alpha_matrix_succ_div a b B hB n i (hd n)]
simp [show i ≠ n + 1 by omega, show i ≠ n by omega]
In a Gegenbauer basis, column \(n\ge 1\) of multiplication has entries \((n+1)/(2(n+\lambda ))\) in row \(n+1\) and \((n+2\lambda -1)/(2(n+\lambda ))\) in row \(n-1\); the diagonal is zero. Column zero has entry \(1/(2\lambda )\) in row one. Over a field the divided formulas require their denominators nonzero; cleared identities hold over commutative rational algebras. For real \(\lambda {\gt}-1/2\), \(\lambda \ne 0\), the matrix has bandwidths \((1,1)\).
theorem Polynomial.gegenbauer_mul_matrix_succ.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer lam k) (n i : ℕ) :
2 * (↑n + lam + 1) * b.toMatrix (fun j => Polynomial.X * Polynomial.gegenbauer lam j) i (n + 1) =
(if i = n + 2 then ↑n + 2 else 0) + if i = n then ↑n + 2 * lam else 0
Lean proof
/-- Cleared multiplication entries in the positive-index columns (DLMF 18.9.1). -/
theorem gegenbauer_mul_matrix_succ
(hb : ∀ k, b k = gegenbauer lam k) (n i : ℕ) :
(2 * (n + lam + 1)) * b.toMatrix (fun j ↦ X * gegenbauer lam j) i (n + 1) =
(if i = n + 2 then (n : R) + 2 else 0) + (if i = n then n + 2 * lam else 0) := by
have h := congrArg (fun p : R[X] ↦ b.repr p i) (gegenbauer_recurrence lam n)
rw [mul_assoc] at h
simp only [← smul_eq_C_mul] at h
simp [← hb, Finsupp.single_apply, eq_comm] at h
change _ * (b.repr (X * gegenbauer lam (n + 1))) i = _
rw [← hb]
split_ifs at h ⊢ <;> first | omega | linear_combination h
theorem Polynomial.gegenbauer_mul_matrix_zero.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer lam k) (i : ℕ) :
2 * lam * b.toMatrix (fun j => Polynomial.X * Polynomial.gegenbauer lam j) i 0 = if i = 1 then 1 else 0
Lean proof
/-- The initial multiplication column (DLMF 18.9.1). -/
theorem gegenbauer_mul_matrix_zero
(hb : ∀ k, b k = gegenbauer lam k) (i : ℕ) :
(2 * lam) * b.toMatrix (fun j ↦ X * gegenbauer lam j) i 0 =
if i = 1 then 1 else 0 := by
have he : C (2 * lam) * (X * gegenbauer lam 0) = gegenbauer lam 1 := by
simp [gegenbauer_one]
have h := congrArg (fun p : R[X] ↦ b.repr p i) he
simp only [← smul_eq_C_mul] at h
simpa [Basis.toMatrix_apply, ← hb, Finsupp.single_apply, eq_comm] using h
theorem Polynomial.gegenbauer_mul_matrix_zero_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (lam : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.gegenbauer lam k) (i : ℕ) (hd : lam ≠ 0) :
B.toMatrix (fun j => Polynomial.X * Polynomial.gegenbauer lam j) i 0 = (if i = 1 then 1 else 0) / (2 * lam)
Lean proof
/-- The divided initial multiplication column (DLMF 18.9.1). -/
theorem gegenbauer_mul_matrix_zero_div
(hB : ∀ k, B k = gegenbauer lam k) (i : ℕ) (hd : lam ≠ 0) :
B.toMatrix (fun j ↦ X * gegenbauer lam j) i 0 =
(if i = 1 then 1 else 0) / (2 * lam) := by
let : CharZero K := Algebra.charZero_of_charZero ℚ K
apply (eq_div_iff (mul_ne_zero (by norm_num) hd)).2
simpa only [mul_comm] using gegenbauer_mul_matrix_zero lam B hB i
/-- Multiplication is tridiagonal (DLMF 18.9.1; Olver--Townsend 2013). -/
theorem gegenbauer_mul_matrix_isBanded
(hB : ∀ k, B k = gegenbauer lam k) (hzero : lam ≠ 0)
(hd : ∀ n : ℕ, (n : K) + lam + 1 ≠ 0) :
(B.toMatrix (fun j ↦ X * gegenbauer lam j)).IsBanded 1 1 := by
intro i j hij
cases j with
| zero =>
rw [gegenbauer_mul_matrix_zero_div lam B hB i hzero]
simp [show i ≠ 1 by omega]
| succ n =>
rw [gegenbauer_mul_matrix_succ_div lam B hB n i (hd n)]
simp [show i ≠ n + 2 by omega, show i ≠ n by omega]
Conversion from parameter \(\lambda \) to \(\lambda +1\) has entries \(\lambda /(n+\lambda )\) in row \(n\) and \(-\lambda /(n+\lambda )\) in row \(n-2\) of column \(n\ge 2\). Column one has entry \(\lambda /(\lambda +1)\) in row one; column zero is the unit column at zero. All other entries vanish. Over a field the divided formulas require their denominators nonzero; cleared identities hold over commutative rational algebras. For real \(\lambda {\gt}-1/2\) the target basis exists and the matrix has bandwidths \((0,2)\), also at the degenerate source parameter zero.
theorem Polynomial.gegenbauer_conversion_matrix_one.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer (lam + 1) k) (i : ℕ) :
(lam + 1) * b.toMatrix (Polynomial.gegenbauer lam) i 1 = if i = 1 then lam else 0
Lean proof
/-- Cleared linear column of parameter conversion (DLMF 18.9.7). -/
theorem gegenbauer_conversion_matrix_one
(hb : ∀ k, b k = gegenbauer (lam + 1) k) (i : ℕ) :
(lam + 1) * b.toMatrix (gegenbauer lam) i 1 = if i = 1 then lam else 0 := by
have h := congrArg (fun p : R[X] ↦ b.repr p i) (gegenbauer_conversion_one lam)
simp only [← smul_eq_C_mul] at h
simpa [Basis.toMatrix_apply, ← hb, Finsupp.single_apply, eq_comm, mul_ite] using h
theorem Polynomial.gegenbauer_conversion_matrix_add_two.{u_1} {R : Type u_1} [CommRing R] [Algebra ℚ R] (lam : R)
(b : Module.Basis ℕ R (Polynomial R)) (hb : ∀ (k : ℕ), b k = Polynomial.gegenbauer (lam + 1) k) (n i : ℕ) :
(↑n + lam + 2) * b.toMatrix (Polynomial.gegenbauer lam) i (n + 2) =
(if i = n + 2 then lam else 0) - if i = n then lam else 0
Lean proof
/-- Cleared conversion entries lie on the diagonal and second superdiagonal
(DLMF 18.9.7). -/
theorem gegenbauer_conversion_matrix_add_two
(hb : ∀ k, b k = gegenbauer (lam + 1) k) (n i : ℕ) :
(n + lam + 2) * b.toMatrix (gegenbauer lam) i (n + 2) =
(if i = n + 2 then lam else 0) - (if i = n then lam else 0) := by
have h := congrArg (fun p : R[X] ↦ b.repr p i) (gegenbauer_conversion lam n)
simp only [← smul_eq_C_mul] at h
simpa [Basis.toMatrix_apply, ← hb, Finsupp.single_apply, eq_comm, mul_sub, mul_ite] using h
theorem Polynomial.gegenbauer_conversion_matrix_one_div.{u_2} {K : Type u_2} [Field K] [Algebra ℚ K] (lam : K)
(B : Module.Basis ℕ K (Polynomial K)) (hB : ∀ (k : ℕ), B k = Polynomial.gegenbauer (lam + 1) k) (i : ℕ)
(hd : lam + 1 ≠ 0) : B.toMatrix (Polynomial.gegenbauer lam) i 1 = (if i = 1 then lam else 0) / (lam + 1)
Lean proof
/-- The linear conversion column in divided form (DLMF 18.9.7). -/
theorem gegenbauer_conversion_matrix_one_div
(hB : ∀ k, B k = gegenbauer (lam + 1) k) (i : ℕ) (hd : lam + 1 ≠ 0) :
B.toMatrix (gegenbauer lam) i 1 = (if i = 1 then lam else 0) / (lam + 1) := by
apply (eq_div_iff hd).2
simpa only [mul_comm] using gegenbauer_conversion_matrix_one lam B hB i
/-- Conversion has lower bandwidth zero and upper bandwidth two
(DLMF 18.9.7; Olver--Townsend 2013). -/
theorem gegenbauer_conversion_matrix_isBanded
(hB : ∀ k, B k = gegenbauer (lam + 1) k)
(hd : ∀ n : ℕ, (n : K) + lam + 1 ≠ 0) :
(B.toMatrix (gegenbauer lam)).IsBanded 0 2 := by
intro i j hij
rcases j with _ | (_ | n)
· rw [gegenbauer_conversion_matrix_zero lam B hB]
exact ite_eq_right (by omega)
· rw [gegenbauer_conversion_matrix_one_div lam B hB i (by simpa using hd 0)]
simp [show i ≠ 1 by omega]
· rw [gegenbauer_conversion_matrix_add_two_div lam B hB n i (by
convert hd (n + 1) using 1
push_cast
ring)]
simp [show i ≠ n + 2 by omega, show i ≠ n by omega]
The conversion matrix of Theorem 4.2.6 for \(\lambda =0.7\) reproduces each \(C_n^{(\lambda )}(x)\) from values of \(C^{(\lambda +1)}\), both computed by the recurrence of Theorem 3.3.6. Its 40 nonzeros lie on the diagonal and the second superdiagonal, the bandwidths \((0,2)\).
function gegenbauer(n, lam, x) # three-term recurrence
n == 0 && return 1.0
a, b = 1.0, 2lam*x
for k in 1:n-1
a, b = b, (2(k + lam)*x*b - (k + 2lam - 1)*a)/(k + 1)
end
b
end
N, lam = 20, 0.7
S = zeros(N+1, N+1) # conversion C^(lam) -> C^(lam+1)
S[1, 1] = 1
S[2, 2] = lam/(lam + 1)
for n in 2:N
S[n+1, n+1] = lam/(n + lam)
S[n-1, n+1] = -lam/(n + lam)
end
x = 0.37
maximum(abs(gegenbauer(n, lam, x) -
sum(S[i+1, n+1]*gegenbauer(i, lam + 1, x) for i in 0:N)) for n in 0:N)
# about 1e-16
band = all(S[i, j] == 0 for i in 1:N+1, j in 1:N+1 if !(0 <= j - i <= 2))
(count(!iszero, S), band) # (40, true)
Theorem
4.2.7Polynomial multiplication bandwidth in Gegenbauer bases
For real Gegenbauer bases with \(\lambda {\gt}-1/2\), \(\lambda \ne 0\), a polynomial multiplier \(p\) has bandwidths \((d,d)\), where \(d=\operatorname {natDegree}p\).
For a field \(K\) and a coefficient count \(n\), the Gegenbauer Clenshaw domain requires \((k+2)\ne 0\) in \(K\) for every \(0\le k{\lt}n-2\). There is no condition when \(n\le 2\).
/-- Nonzero denominators at exactly the recurrence indices used by an expansion. -/
def GegenbauerClenshawInput (K : Type*) [Field K] (n : ℕ) : Prop :=
∀ i : Fin (n - 2), (i.val : K) + 2 ≠ 0
Over a field with a rational algebra structure, \(k+2\ne 0\) for every \(k\in \mathbb {N}\). Thus every coefficient count \(n\) satisfies the Gegenbauer Clenshaw denominator conditions of Definition 4.2.8.
Lean Formalisation
theorem Polynomial.GegenbauerClenshawInput.ofRatAlgebra.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K] (n : ℕ) :
Polynomial.GegenbauerClenshawInput K n
Lean proof
/-- Rational algebras over fields admit every finite Gegenbauer recurrence. -/
theorem GegenbauerClenshawInput.ofRatAlgebra (n : ℕ) :
GegenbauerClenshawInput K n := by
let : CharZero K := Algebra.charZero_of_charZero ℚ K
intro i
exact_mod_cast (show i.val + 2 ≠ 0 by omega)
For a field \(K\), parameters \(\lambda ,x\in K\), \(n\) coefficients \(c_0,\ldots ,c_{n-1}\), and the denominator conditions of Definition 4.2.8, use finite Clenshaw evaluation with
theorem Polynomial.clenshawGegenbauer_eq_sum.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K] (lam x : K) (c : ℕ → K) (n : ℕ) :
Polynomial.clenshawGegenbauer lam x c n ⋯ =
∑ i ∈ Finset.range n, c i * Polynomial.eval x (Polynomial.gegenbauer lam i)
Lean proof
/-- Clenshaw evaluation is exact for every Gegenbauer parameter. -/
theorem clenshawGegenbauer_eq_sum (lam x : K) (c : ℕ → K) (n : ℕ) :
clenshawGegenbauer lam x c n =
∑ i ∈ Finset.range n, c i * (gegenbauer lam i).eval x := by
let : CharZero K := Algebra.charZero_of_charZero ℚ K
have hp (k : ℕ) : (gegenbauer lam (k + 2)).eval x =
(2 * (k + lam + 1) * x / (k + 2)) * (gegenbauer lam (k + 1)).eval x +
(-(k + 2 * lam) / (k + 2)) * (gegenbauer lam k).eval x := by
have hd : (k : K) + 2 ≠ 0 := by exact_mod_cast (show k + 2 ≠ 0 by omega)
have h := congrArg (fun p : K[X] ↦ p.eval x) (gegenbauer_recurrence lam k)
simp only [eval_sub, eval_add, eval_mul, eval_C, eval_X, eval_zero] at h
field_simp [hd]
linear_combination h
have he := clenshaw_eq_sum _ _ c (fun k ↦ (gegenbauer lam k).eval x) hp n
have hf := finiteClenshaw_eq
(fun k ↦ 2 * (k + lam + 1) * x / (k + 2))
(fun k ↦ -(k + 2 * lam) / (k + 2)) c 1 (2 * lam * x) n
simpa [clenshawGegenbauer] using hf.trans (by simpa using he)
For a field \(K\), parameters \(\alpha ,\beta \in K\) and a coefficient count \(n\), the Jacobi Clenshaw domain requires \(2\ne 0\) when \(n\ge 2\), and
In a field with a rational algebra structure, if \(d_k\ne 0\) for every \(k\ge 0\), the denominator conditions of Definition 4.2.12 hold for every coefficient count \(n\). For real \(\alpha ,\beta {\gt}-1\), these denominator conditions hold without further assumptions.
/-- Positivity in the real orthogonality range certifies every finite input. -/
theorem JacobiClenshawInput.of_neg_one_lt {α β : ℝ} (hα : -1 < α) (hβ : -1 < β)
(n : ℕ) : JacobiClenshawInput α β n := by
apply JacobiClenshawInput.ofDenominators
intro k
have hk : (0 : ℝ) ≤ k := Nat.cast_nonneg k
have h₁ : (0 : ℝ) < k + α + β + 2 := by linarith
have h₂ : (0 : ℝ) < 2 * k + α + β + 2 := by linarith
positivity
For a field \(K\), parameters \(\alpha ,\beta ,x\in K\), \(n\) coefficients \(c_0,\ldots ,c_{n-1}\), and the denominator conditions of Definition 4.2.12, return \(0\) if \(n=0\) and \(c_0\) if \(n=1\). For \(n\ge 2\), use finite Clenshaw evaluation with
with \(p_0=1\) and \(p_1=\alpha +1+\tfrac 12(\alpha +\beta +2)(x-1)\). The evaluator returns \(\sum _{i=0}^{n-1}c_iP_i^{(\alpha ,\beta )}(x)\). For real \(\alpha ,\beta {\gt}-1\), all \(d_k\) are positive and no extra hypotheses are needed. In particular, \(\alpha +\beta =-1\) is included.
theorem Polynomial.clenshawJacobi_eq_sum_of_neg_one_lt {α β : ℝ} (hα : -1 < α) (hβ : -1 < β) (x : ℝ) (c : ℕ → ℝ) (n : ℕ) :
Polynomial.clenshawJacobi α β x c n ⋯ = ∑ i ∈ Finset.range n, c i * Polynomial.eval x (Polynomial.jacobi α β i)
Lean proof
/-- Throughout the real orthogonality range, no extra division conditions are needed. -/
theorem clenshawJacobi_eq_sum_of_neg_one_lt {α β : ℝ} (hα : -1 < α) (hβ : -1 < β)
(x : ℝ) (c : ℕ → ℝ) (n : ℕ) :
clenshawJacobi α β x c n (JacobiClenshawInput.of_neg_one_lt hα hβ n) =
∑ i ∈ Finset.range n, c i * (jacobi α β i).eval x := by
have hd (k : ℕ) :
2 * (k + 2 : ℝ) * (k + α + β + 2) * (2 * k + α + β + 2) ≠ 0 := by
have hk : (0 : ℝ) ≤ k := Nat.cast_nonneg k
have h₁ : (0 : ℝ) < k + α + β + 2 := by linarith
have h₂ : (0 : ℝ) < 2 * k + α + β + 2 := by linarith
positivity
exact clenshawJacobi_eq_sum α β x c hd n
Chebyshev expansions enter the ultraspherical bases through \(C^{(1)}=U\). Conversion \(T\to C^{(1)}\) has bandwidth \((0,2)\), and the \(k\)th derivative maps \(T\) to \(C^{(k)}\) with a single nonzero diagonal \(k\) places above the main one. Multiplication in the \(T\) basis has a Toeplitz-plus-Hankel form. The entry formula below includes the adjustments required by the full constant term.
Over a commutative rational algebra, \(C_n^{(1)}=U_n\) and \(2T_{n+2}=C_{n+2}^{(1)}-C_n^{(1)}\). For \(k,n\ge 0\),
\[ D^{k+1}T_{n+k+1}=2^k k!(n+k+1)C_n^{(k+1)}. \]
Over a characteristic-zero field, \(D^kT_n=0\) when \(n{\lt}k\). These identities retain the full constant coefficient convention.
References: [DLMF, 18.7.4 and 18.9.9]; [OT13, §2].
Lean Formalisation
theorem Polynomial.gegenbauer_one_eq_chebyshev_U.{u_1} (R : Type u_1) [CommRing R] [Algebra ℚ R] (n : ℕ) :
Polynomial.gegenbauer 1 n = Polynomial.Chebyshev.U R ↑n
Lean proof
/-- Parameter-one Gegenbauer polynomials are Chebyshev U, with no rescaling
(DLMF 18.7.4). -/
theorem gegenbauer_one_eq_chebyshev_U (R : Type*) [CommRing R] [Algebra ℚ R] (n : ℕ) :
gegenbauer (1 : R) n = Chebyshev.U R n := by
let f : ℚ →ₐ[ℚ] R := Algebra.ofId ℚ R
have h := congrArg (Polynomial.map f.toRingHom) (gegenbauer_one_eq_U_rat n)
simpa only [map_gegenbauer, map_one, Chebyshev.map_U] using h
/-- The positive-degree conversion from T to the first ultraspherical family,
with the factor two cleared (Olver–Townsend, equation 2.8). -/
theorem two_mul_chebyshev_T_eq_gegenbauer_sub (R : Type*) [CommRing R] [Algebra ℚ R]
(n : ℕ) :
2 * Chebyshev.T R (n + 2) = gegenbauer (1 : R) (n + 2) - gegenbauer (1 : R) n := by
simp only [gegenbauer_one_eq_chebyshev_U, Nat.cast_add, Nat.cast_ofNat]
exact Chebyshev.two_mul_T_eq_U_sub_U R n
theorem Polynomial.iterate_derivative_chebyshev_T.{u_1} (R : Type u_1) [CommRing R] [Algebra ℚ R] (k n : ℕ) :
(⇑Polynomial.derivative)^[k + 1] (Polynomial.Chebyshev.T R ↑(n + k + 1)) =
Polynomial.C (2 ^ k * ↑k.factorial * (↑n + ↑k + 1)) * Polynomial.gegenbauer (↑k + 1) n
Lean proof
/-- Repeated differentiation has a single ultraspherical output degree
(Olver–Townsend, Section 3). The index form includes every nonzero case. -/
theorem iterate_derivative_chebyshev_T (R : Type*) [CommRing R] [Algebra ℚ R]
(k n : ℕ) :
derivative^[k + 1] (Chebyshev.T R (n + k + 1 : ℕ)) =
C ((2 : R) ^ k * k.factorial * (n + k + 1)) * gegenbauer (k + 1 : R) n := by
induction k generalizing n with
| zero => simpa using derivative_chebyshev_T_succ R n
| succ k ih =>
rw [Function.iterate_succ_apply']
rw [show n + (k + 1) + 1 = (n + 1) + k + 1 by omega, ih,
derivative_C_mul, derivative_gegenbauer_succ]
simp only [Nat.cast_add, Nat.cast_one, Nat.factorial_succ, Nat.cast_mul,
pow_succ, ← mul_assoc, ← map_mul]
congr 2
ring
Over a field with a rational algebra structure, take a target polynomial basis \(c_i=C_i^{(1)}\). With rows indexing output coefficients and columns input coefficients, conversion \(S\) from \(T\) has columns
theorem Polynomial.chebyshev_gegenbauer_conversion_one.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K]
(b : Module.Basis ℕ K (Polynomial K)) (hb : ∀ (j : ℕ), b j = Polynomial.gegenbauer 1 j) (i : ℕ) :
b.toMatrix (fun j => Polynomial.Chebyshev.T K ↑j) i 1 = (if i = 1 then 1 else 0) / 2
Lean proof
/-- The linear conversion column carries the factor one half (2.8). -/
theorem chebyshev_gegenbauer_conversion_one
(hb : ∀ j, b j = gegenbauer (1 : K) j) (i : ℕ) :
b.toMatrix (fun j : ℕ ↦ Chebyshev.T K j) i 1 = (if i = 1 then 1 else 0) / 2 := by
have : CharZero K := Algebra.charZero_of_charZero ℚ K
have he : 2 * Chebyshev.T K 1 = gegenbauer (1 : K) 1 := by
simp [Chebyshev.T_one, gegenbauer_one, map_ofNat]
have h := congrArg (fun p : K[X] ↦ b.repr p i) he
rw [← C_ofNat 2, ← smul_eq_C_mul] at h
simp only [map_smul, Finsupp.smul_apply, smul_eq_mul, ← hb, b.repr_self,
Finsupp.single_apply] at h
apply (eq_div_iff (by norm_num : (2 : K) ≠ 0)).2
simpa [Basis.toMatrix_apply, eq_comm, mul_comm] using h
theorem Polynomial.chebyshev_gegenbauer_conversion_add_two.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K]
(b : Module.Basis ℕ K (Polynomial K)) (hb : ∀ (j : ℕ), b j = Polynomial.gegenbauer 1 j) (n i : ℕ) :
b.toMatrix (fun j => Polynomial.Chebyshev.T K ↑j) i (n + 2) =
((if i = n + 2 then 1 else 0) - if i = n then 1 else 0) / 2
Lean proof
/-- The remaining conversion columns have entries one half and minus one half (2.8). -/
theorem chebyshev_gegenbauer_conversion_add_two
(hb : ∀ j, b j = gegenbauer (1 : K) j) (n i : ℕ) :
b.toMatrix (fun j : ℕ ↦ Chebyshev.T K j) i (n + 2) =
((if i = n + 2 then 1 else 0) - (if i = n then 1 else 0)) / 2 := by
have : CharZero K := Algebra.charZero_of_charZero ℚ K
have h := congrArg (fun p : K[X] ↦ b.repr p i) (two_mul_chebyshev_T_eq_gegenbauer_sub K n)
rw [← C_ofNat 2, ← smul_eq_C_mul] at h
simp only [map_smul, map_sub, Finsupp.smul_apply, Finsupp.sub_apply, smul_eq_mul,
← hb, b.repr_self, Finsupp.single_apply] at h
apply (eq_div_iff (by norm_num : (2 : K) ≠ 0)).2
simpa [Basis.toMatrix_apply, eq_comm, mul_comm] using h
theorem Polynomial.chebyshev_gegenbauer_conversion_isBanded.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K]
(b : Module.Basis ℕ K (Polynomial K)) (hb : ∀ (j : ℕ), b j = Polynomial.gegenbauer 1 j) :
(b.toMatrix fun j => Polynomial.Chebyshev.T K ↑j).IsBanded 0 2
Lean proof
/-- Chebyshev-to-ultraspherical conversion has bandwidths `(0,2)` (2.8). -/
theorem chebyshev_gegenbauer_conversion_isBanded
(hb : ∀ j, b j = gegenbauer (1 : K) j) :
(b.toMatrix (fun j : ℕ ↦ Chebyshev.T K j)).IsBanded 0 2 := by
intro i j hij
rcases j with _ | (_ | n)
· rw [chebyshev_gegenbauer_conversion_zero b hb]
exact ite_eq_right (by omega)
· rw [chebyshev_gegenbauer_conversion_one b hb]
simp [show i ≠ 1 by omega]
· rw [chebyshev_gegenbauer_conversion_add_two b hb]
simp [show i ≠ n + 2 by omega, show i ≠ n by omega]
with columns below \(k+1\) zero. Its bandwidths are \((0,k+1)\). These identities hold over a field with a rational algebra structure and are instantiated on the real polynomial bases.
theorem Polynomial.chebyshev_iterate_derivative_matrix_zero.{u_1} {K : Type u_1} [Field K] [Algebra ℚ K]
(b : Module.Basis ℕ K (Polynomial K)) (k i j : ℕ) (hj : j < k) :
b.toMatrix (fun n => (⇑Polynomial.derivative)^[k] (Polynomial.Chebyshev.T K ↑n)) i j = 0
Lean proof
/-- Columns below the derivative order vanish (Olver--Townsend, Section 3). -/
theorem chebyshev_iterate_derivative_matrix_zero (k i j : ℕ) (hj : j < k) :
b.toMatrix (fun n : ℕ ↦ derivative^[k] (Chebyshev.T K n)) i j = 0 := by
have : CharZero K := Algebra.charZero_of_charZero ℚ K
rw [Basis.toMatrix_apply, iterate_derivative_chebyshev_T_eq_zero K hj]
simp
In particular the positive diagonal is \(a_0+a_{2i}/2\). These are the Toeplitz-plus-Hankel entries with the exceptional row, column and constant coefficient accounted for.
theorem Polynomial.two_mul_chebyshevBasis_repr_mul (m j i : ℕ) :
2 * (Polynomial.chebyshevBasis.repr (Polynomial.chebyshevBasis m * Polynomial.chebyshevBasis j)) i =
(if i = m + j then 1 else 0) + if i = (↑m - ↑j).natAbs then 1 else 0
Lean proof
/-- Coordinates of a product of two Chebyshev modes, with the factor two cleared. -/
theorem two_mul_chebyshevBasis_repr_mul (m j i : ℕ) :
2 * chebyshevBasis.repr (chebyshevBasis m * chebyshevBasis j) i =
(if i = m + j then 1 else 0) +
(if i = ((m : ℤ) - j).natAbs then 1 else 0) := by
have h := congrArg (fun p : ℝ[X] ↦ chebyshevBasis.repr p i) (Chebyshev.T_mul_T ℝ m j)
rw [mul_assoc, ← C_ofNat 2, ← smul_eq_C_mul] at h
have ha : Chebyshev.T ℝ ((m : ℤ) + j) = chebyshevBasis (m + j) := by
simp [chebyshevBasis_apply]
have hs : Chebyshev.T ℝ ((m : ℤ) - j) = chebyshevBasis ((m : ℤ) - j).natAbs := by
rw [chebyshevBasis_apply, Chebyshev.T_natAbs]
rw [ha, hs, ← chebyshevBasis_apply m, ← chebyshevBasis_apply j] at h
simpa only [map_smul, Finsupp.smul_apply, smul_eq_mul, map_add, Finsupp.add_apply,
Basis.repr_self, Finsupp.single_apply, eq_comm] using h
theorem Polynomial.chebyshev_mul_matrix_zero_column (p : Polynomial ℝ) (i : ℕ) :
Polynomial.chebyshevBasis.toMatrix (fun j => p * Polynomial.chebyshevBasis j) i 0 =
(Polynomial.chebyshevBasis.repr p) i
Lean proof
/-- Column zero is the multiplier's own Chebyshev coefficient vector. -/
theorem chebyshev_mul_matrix_zero_column (p : ℝ[X]) (i : ℕ) :
chebyshevBasis.toMatrix (fun j ↦ p * chebyshevBasis j) i 0 = chebyshevBasis.repr p i := by
simp [Basis.toMatrix_apply, chebyshevBasis_apply, Chebyshev.T_zero]
/-- Positive-row, positive-column multiplication entries, displaying the extra
constant-coefficient contribution on the diagonal (Olver--Townsend, 2.7). -/
theorem chebyshev_mul_matrix_positive (p : ℝ[X]) {i j : ℕ} (hi : 0 < i) (hj : 0 < j) :
chebyshevBasis.toMatrix (fun j ↦ p * chebyshevBasis j) i j =
((if i = j then 2 else 1) * chebyshevBasis.repr p ((i : ℤ) - j).natAbs +
chebyshevBasis.repr p (i + j)) / 2 := by
have h : (2 : ℝ) • ((chebyshevBasis.coord i).comp (LinearMap.mulRight ℝ (chebyshevBasis j))) =
(if i = j then (2 : ℝ) else 1) • chebyshevBasis.coord ((i : ℤ) - j).natAbs +
chebyshevBasis.coord (i + j) := by
apply chebyshevBasis.ext
intro m
change 2 * chebyshevBasis.repr (chebyshevBasis m * chebyshevBasis j) i =
(if i = j then 2 else 1) * chebyshevBasis.repr (chebyshevBasis m) ((i : ℤ) - j).natAbs +
chebyshevBasis.repr (chebyshevBasis m) (i + j)
rw [two_mul_chebyshevBasis_repr_mul]
simp only [Basis.repr_self, Finsupp.single_apply]
have hdiff (a b : ℕ) : ((a : ℤ) - b).natAbs = if b ≤ a then a - b else b - a := by
split_ifs with hab
· exact Int.natAbs_natCast_sub_natCast_of_ge hab
· exact Int.natAbs_natCast_sub_natCast_of_le (by omega)
simp only [hdiff]
split_ifs <;> first | omega | norm_num
have he := congrArg (fun L : ℝ[X] →ₗ[ℝ] ℝ ↦ L p) h
change 2 * chebyshevBasis.repr (p * chebyshevBasis j) i =
(if i = j then 2 else 1) * chebyshevBasis.repr p ((i : ℤ) - j).natAbs +
chebyshevBasis.repr p (i + j) at he
change chebyshevBasis.repr (p * chebyshevBasis j) i = _
linarith
Conversion \(B_k\to B_{k+r}\) has bandwidths \((0,2r)\). Differentiation \(D^k\) from \(B_0\) to \(B_k\) has bandwidths \((0,k)\), including \(k=0\). Consequently, for \(0\le k\le N\), differentiation represented from \(B_0\) to \(B_N\) has bandwidths \((0,2N-k)\).
/-- Conversion through r successive levels has upper bandwidth 2*r. -/
theorem ultrasphericalBasis_raise_isBanded (k r : ℕ) :
((ultrasphericalBasis (k + r)).toMatrix (ultrasphericalBasis k)).IsBanded 0 (2 * r) := by
induction r with
| zero =>
intro i j hij
simp only [Nat.add_zero, Basis.toMatrix_apply, Basis.repr_self, Finsupp.single_apply]
exact ite_eq_right (by omega)
| succ r ih =>
have h := (ultrasphericalBasis k).toMatrix_comp_isBanded
(ultrasphericalBasis (k + r)) (ultrasphericalBasis (k + r + 1))
LinearMap.id LinearMap.id ih (ultrasphericalBasis_step_isBanded (k + r))
convert h using 1
/-- Conversion to any later level has upper bandwidth twice the level difference. -/
theorem ultrasphericalBasis_conversion_isBanded {k N : ℕ} (hk : k ≤ N) :
((ultrasphericalBasis N).toMatrix (ultrasphericalBasis k)).IsBanded 0 (2 * (N - k)) := by
simpa only [Nat.add_sub_of_le hk] using ultrasphericalBasis_raise_isBanded k (N - k)
theorem Polynomial.ultrasphericalBasis_derivative_isBanded (k : ℕ) :
((Polynomial.ultrasphericalBasis k).toMatrix fun j =>
(⇑Polynomial.derivative)^[k] (Polynomial.chebyshevBasis j)).IsBanded
0 k
Lean proof
/-- Order-k differentiation reaches its natural level with upper bandwidth k. -/
theorem ultrasphericalBasis_derivative_isBanded (k : ℕ) :
((ultrasphericalBasis k).toMatrix
(fun j ↦ derivative^[k] (chebyshevBasis j))).IsBanded 0 k := by
cases k with
| zero =>
intro i j hij
simp only [Function.iterate_zero_apply, ultrasphericalBasis_zero,
Basis.toMatrix_apply, Basis.repr_self, Finsupp.single_apply]
exact ite_eq_right (by omega)
| succ k => exact chebyshevBasis_iterate_derivative_isBanded k
theorem Polynomial.ultrasphericalBasis_derivative_to_level_isBanded {k N : ℕ} (hk : k ≤ N) :
((Polynomial.ultrasphericalBasis N).toMatrix fun j =>
(⇑Polynomial.derivative)^[k] (Polynomial.chebyshevBasis j)).IsBanded
0 (2 * N - k)
Lean proof
/-- Every derivative can be represented in a common later level N, with the
conversion cost made explicit (Olver--Townsend, Section 3). -/
theorem ultrasphericalBasis_derivative_to_level_isBanded {k N : ℕ} (hk : k ≤ N) :
((ultrasphericalBasis N).toMatrix
(fun j ↦ derivative^[k] (chebyshevBasis j))).IsBanded 0 (2 * N - k) := by
have h := chebyshevBasis.toMatrix_comp_isBanded (ultrasphericalBasis k)
(ultrasphericalBasis N) (derivative ^ k) LinearMap.id
(by simpa only [Module.End.pow_apply] using ultrasphericalBasis_derivative_isBanded k)
(ultrasphericalBasis_conversion_isBanded hk)
have he : k + 2 * (N - k) = 2 * N - k := by omega
simpa only [LinearMap.id_apply, Module.End.pow_apply, Nat.zero_add, he] using h
Use the existing real bases \(B_0=T\), \(B_k=C^{(k)}\) for \(k\ge 1\), evaluated at complex arguments. For \(k\le N\), conversion from \(B_k\) to \(B_N\) computes coordinate \(i\) from indices \(j{\lt}i+2(N-k)+1\). Under the weighted summability condition of matrix reconstruction, it preserves the represented function. In either direction, the weighted summability condition gives reconstruction by the contributions \(\gamma _i\) of Theorem 4.1.15. For reverse conversion, these may be factored into coefficients and modes when each coefficient row converges. Forward conversion has finite rows, so this additional row convergence is automatic.
Lean Formalisation
theorem Polynomial.ultraspherical_series_conversion_eq_sum {k N : ℕ} (hk : k ≤ N) (a : ℕ → ℂ) (i : ℕ) :
(Polynomial.ultrasphericalBasis k).seriesCoefficientMap (Polynomial.ultrasphericalBasis N) LinearMap.id
Complex.ofRealHom
(Module.Basis.SeriesCoefficientInput.ofBanded (Polynomial.ultrasphericalBasis k)
(Polynomial.ultrasphericalBasis N) LinearMap.id Complex.ofRealHom a ⋯ i) =
∑ j ∈ Finset.range (i + 2 * (N - k) + 1),
a j * ↑(((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)) i)
Lean proof
/-- Raising levels computes each certified output coefficient from a finite window. -/
theorem ultraspherical_series_conversion_eq_sum {k N : ℕ} (hk : k ≤ N)
(a : ℕ → ℂ) (i : ℕ) :
(ultrasphericalBasis k).seriesCoefficientMap (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom (.ofBanded _ _ _ _ a
(ultrasphericalBasis_conversion_isBanded hk) i) =
∑ j ∈ Finset.range (i + 2 * (N - k) + 1),
a j * ((ultrasphericalBasis N).repr (ultrasphericalBasis k j) i : ℂ) :=
(ultrasphericalBasis k).seriesCoefficientMap_eq_sum_of_isBanded
(ultrasphericalBasis N) LinearMap.id Complex.ofRealHom a
(ultrasphericalBasis_conversion_isBanded hk) i
theorem Polynomial.hasSum_ultraspherical_series_conversion (k N : ℕ) (a : ℕ → ℂ) (z : ℂ) (w : ℕ → ℝ)
(hw : ∀ (i : ℕ), ‖Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis N) i)‖ ≤ w i)
(ha :
Summable fun j =>
‖a j‖ *
∑ i ∈ ((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)).support,
‖↑(((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)) i)‖ * w i) :
HasSum (fun i => Polynomial.regroupCoefficients (Polynomial.RegroupCoefficientInput.ofSummableNorm ⋯ Prod.snd i))
(∑' (j : ℕ), a j * Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis k) j))
Lean proof
/-- Weighted reconstruction holds in either direction, including zero modes. -/
theorem hasSum_ultraspherical_series_conversion (k N : ℕ) (a : ℕ → ℂ) (z : ℂ)
(w : ℕ → ℝ)
(hw : ∀ i, ‖(ultrasphericalBasis N i).eval₂ Complex.ofRealHom z‖ ≤ w i)
(ha : Summable (fun j ↦ ‖a j‖ *
∑ i ∈ ((ultrasphericalBasis N).repr (ultrasphericalBasis k j)).support,
‖(((ultrasphericalBasis N).repr (ultrasphericalBasis k j)) i : ℂ)‖ * w i)) :
HasSum (fun i ↦ regroupCoefficients (RegroupCoefficientInput.ofSummableNorm
((ultrasphericalBasis k).summable_norm_seriesCoefficientMap_terms (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom a z w hw ha) Prod.snd i))
(∑' j, a j * (ultrasphericalBasis k j).eval₂ Complex.ofRealHom z) :=
(ultrasphericalBasis k).hasSum_seriesCoefficientMap (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom a z
((ultrasphericalBasis k).summable_norm_seriesCoefficientMap_terms (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom a z w hw ha)
theorem Polynomial.hasSum_ultraspherical_series_conversion_of_rows (k N : ℕ) (a : ℕ → ℂ) (z : ℂ) (w : ℕ → ℝ)
(hw : ∀ (i : ℕ), ‖Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis N) i)‖ ≤ w i)
(ha :
Summable fun j =>
‖a j‖ *
∑ i ∈ ((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)).support,
‖↑(((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)) i)‖ * w i)
(rows :
(i : ℕ) →
(Polynomial.ultrasphericalBasis k).SeriesCoefficientInput (Polynomial.ultrasphericalBasis N) LinearMap.id
Complex.ofRealHom i)
(hrows : ∀ (i : ℕ), ↑(rows i) = a) :
HasSum
(fun i =>
(Polynomial.ultrasphericalBasis k).seriesCoefficientMap (Polynomial.ultrasphericalBasis N) LinearMap.id
Complex.ofRealHom (rows i) *
Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis N) i))
(∑' (j : ℕ), a j * Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis k) j))
Lean proof
/-- With convergent coefficient rows the weighted reconstruction factors into
coefficients times basis modes, for either direction of conversion. -/
theorem hasSum_ultraspherical_series_conversion_of_rows (k N : ℕ) (a : ℕ → ℂ) (z : ℂ)
(w : ℕ → ℝ)
(hw : ∀ i, ‖(ultrasphericalBasis N i).eval₂ Complex.ofRealHom z‖ ≤ w i)
(ha : Summable (fun j ↦ ‖a j‖ *
∑ i ∈ ((ultrasphericalBasis N).repr (ultrasphericalBasis k j)).support,
‖(((ultrasphericalBasis N).repr (ultrasphericalBasis k j)) i : ℂ)‖ * w i))
(rows : ∀ i, (ultrasphericalBasis k).SeriesCoefficientInput (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom i) (hrows : ∀ i, (rows i).val = a) :
HasSum (fun i ↦ (ultrasphericalBasis k).seriesCoefficientMap (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom (rows i) * (ultrasphericalBasis N i).eval₂ Complex.ofRealHom z)
(∑' j, a j * (ultrasphericalBasis k j).eval₂ Complex.ofRealHom z) :=
(ultrasphericalBasis k).hasSum_seriesCoefficientMap_of_rows (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom a z
((ultrasphericalBasis k).summable_norm_seriesCoefficientMap_terms (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom a z w hw ha) rows hrows
theorem Polynomial.hasSum_ultraspherical_series_conversion_of_le {k N : ℕ} (hk : k ≤ N) (a : ℕ → ℂ) (z : ℂ) (w : ℕ → ℝ)
(hw : ∀ (i : ℕ), ‖Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis N) i)‖ ≤ w i)
(ha :
Summable fun j =>
‖a j‖ *
∑ i ∈ ((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)).support,
‖↑(((Polynomial.ultrasphericalBasis N).repr ((Polynomial.ultrasphericalBasis k) j)) i)‖ * w i) :
HasSum
(fun i =>
(Polynomial.ultrasphericalBasis k).seriesCoefficientMap (Polynomial.ultrasphericalBasis N) LinearMap.id
Complex.ofRealHom
(Module.Basis.SeriesCoefficientInput.ofBanded (Polynomial.ultrasphericalBasis k)
(Polynomial.ultrasphericalBasis N) LinearMap.id Complex.ofRealHom a ⋯ i) *
Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis N) i))
(∑' (j : ℕ), a j * Polynomial.eval₂ Complex.ofRealHom z ((Polynomial.ultrasphericalBasis k) j))
Lean proof
/-- Raising levels supplies convergent rows automatically by bandedness. -/
theorem hasSum_ultraspherical_series_conversion_of_le {k N : ℕ} (hk : k ≤ N)
(a : ℕ → ℂ) (z : ℂ) (w : ℕ → ℝ)
(hw : ∀ i, ‖(ultrasphericalBasis N i).eval₂ Complex.ofRealHom z‖ ≤ w i)
(ha : Summable (fun j ↦ ‖a j‖ *
∑ i ∈ ((ultrasphericalBasis N).repr (ultrasphericalBasis k j)).support,
‖(((ultrasphericalBasis N).repr (ultrasphericalBasis k j)) i : ℂ)‖ * w i)) :
HasSum (fun i ↦ (ultrasphericalBasis k).seriesCoefficientMap (ultrasphericalBasis N)
LinearMap.id Complex.ofRealHom (.ofBanded _ _ _ _ a
(ultrasphericalBasis_conversion_isBanded hk) i) *
(ultrasphericalBasis N i).eval₂ Complex.ofRealHom z)
(∑' j, a j * (ultrasphericalBasis k j).eval₂ Complex.ofRealHom z) :=
hasSum_ultraspherical_series_conversion_of_rows k N a z w hw ha _ (fun _ ↦ rfl)
A differential equation combines these maps. Each differentiated term first lands in its own basis; conversion brings the terms to a common target so that their coefficient matrices can be added.