@@ -15,179 +15,153 @@ public import Mathlib.Topology.Algebra.Polynomial
1515
1616* Chebyshev polynomials minimize deviation from zero,
1717 following proof in https://math.stackexchange.com/a/978145/1277
18+ [SWITCH TO STATEMENT]
19+ * Chebyshev polynomials maximize iterated derivatives at 1 and beyond, using similar idea
1820
1921 ## Main statements
2022
21- * `le_sup_abs_eval_of_monic` provides a lower bound on the maximum of |P(x)| on [-1, 1] for monic P
22- * `sup_abs_eval_eq_iff_of_monic` characterizes the equality case
23+ [ STATEMENTS ]
2324-/
24-
25+ @[expose] public section
2526namespace Polynomial.Chebyshev
2627
2728open Polynomial Real
2829
29- lemma mem_Icc {n j : ℕ} (hn : n ≠ 0 ) (hj : j ∈ Finset.range (n + 1 )) : j * π / n ∈ Set.Icc 0 π := by
30- refine ⟨by positivity, ?_⟩
31- · replace hj : (j : ℝ) ≤ n := Finset.mem_range.mp hj |> Nat.le_of_lt_succ |> Nat.cast_le.mpr
32- linear_combination (norm := (field_simp; ring_nf; rfl)) (π / n) * hj
33-
34- lemma prod_pos {n : ℕ} {i : ℕ} (hi : i ∈ Finset.range (n + 1 )) :
35- 0 < (-1 ) ^ i * ∏ j ∈ (Finset.range (n + 1 )).erase i, (cos (i * π / n) - cos (j * π / n)) := by
36- by_cases n = 0
37- case pos hn => aesop
38- case neg hn =>
39- have h₁ : 0 < ∏ j ∈ Finset.range i, ((-1 ) * (cos (i * π / n) - cos (j * π / n))) := by
40- apply Finset.prod_pos
41- intro j hj
42- have : cos (i * π / n) < cos (j * π / n) := by
43- apply Real.strictAntiOn_cos (mem_Icc hn (by grind)) (mem_Icc hn hi)
44- have : (j : ℝ) < i := by aesop
45- linear_combination (π / n) * this
46- linarith
30+ /-- For n ≠ 0 and i ≤ n, `chebyshevNode n i` is one of the extremal points of the Chebyhsev T
31+ polynomial over the interval [-1, 1]. -/
32+ noncomputable abbrev chebyshevNode (n i : ℕ) : ℝ := cos (i * π / n)
33+
34+ lemma chebyshevNode_eq_one {n : ℕ} : chebyshevNode n 0 = 1 := by simp [chebyshevNode]
35+
36+ lemma chebyshevNode_eq_neg_one {n : ℕ} (hn : n ≠ 0 ) : chebyshevNode n n = -1 := by
37+ have : n * π / n = π := by aesop
38+ simp [chebyshevNode, this]
39+
40+ lemma chebyshevNode_mem_Icc {n i : ℕ} : chebyshevNode n i ∈ Set.Icc (-1 ) 1 :=
41+ Set.mem_Icc.mpr ⟨neg_one_le_cos _, cos_le_one _⟩
42+
43+ lemma eval_T_real_chebyshevNode {n i : ℕ} (hn : n ≠ 0 ) :
44+ (T ℝ n).eval (chebyshevNode n i) = (-1 ) ^ i := by
45+ have : (n : ℤ) * (i * π / n) = i * π := by norm_cast; field
46+ rw [T_real_cos, this, cos_nat_mul_pi]
47+
48+ lemma strictAntiOn_chebyshevNode (n : ℕ) :
49+ StrictAntiOn (chebyshevNode n ·) (Finset.range (n + 1 )) := by
50+ wlog hn : n ≠ 0
51+ · push_neg at hn
52+ simp [hn]
53+ refine strictAntiOn_cos.comp_strictMonoOn ?_ (fun x hx => Set.mem_Icc.mpr ⟨by positivity, ?_⟩)
54+ · apply StrictMono.strictMonoOn
55+ exact StrictMono.mul_const
56+ (StrictMono.mul_const Nat.strictMono_cast (by positivity)) (by positivity)
57+ rw [Finset.mem_coe, Finset.mem_range_succ_iff] at hx
58+ rw [mul_div_assoc]
59+ nth_rewrite 2 [← mul_div_cancel₀ π (Nat.cast_ne_zero.mpr hn)]
60+ exact mul_le_mul_of_nonneg_right (Nat.cast_le.mpr hx) (by positivity)
61+
62+ lemma chebyshevNode_lt {n i j : ℕ} (hi : i ≤ n) (hj : j ≤ n) (hij : i < j) :
63+ chebyshevNode n j < chebyshevNode n i :=
64+ (strictAntiOn_chebyshevNode n) (Finset.mem_coe.mpr (Finset.mem_range_succ_iff.mpr hi))
65+ (Finset.mem_coe.mpr (Finset.mem_range_succ_iff.mpr hj)) hij
66+
67+ lemma zero_lt_prod_chebyshevNode_sub_chebyshevNode {n i : ℕ} (hi : i ≤ n) :
68+ 0 < (-1 ) ^ i * ∏ j ∈ (Finset.range (n + 1 )).erase i, (chebyshevNode n i - chebyshevNode n j) :=
69+ by
70+ wlog hn : n ≠ 0
71+ · push_neg at hn
72+ replace hi : i = 0 := Nat.le_zero.mp (le_of_le_of_eq hi hn)
73+ simp [hn, hi]
74+ have h₁ : 0 < ∏ j ∈ Finset.range i, ((-1 ) * (chebyshevNode n i - chebyshevNode n j)) :=
75+ Finset.prod_pos (fun j hj => mul_pos_of_neg_of_neg neg_one_lt_zero <| sub_neg.mpr <|
76+ chebyshevNode_lt (le_trans (le_of_lt <| Finset.mem_range.mp hj) hi) hi
77+ (Finset.mem_range.mp hj))
4778 rw [Finset.prod_mul_distrib, Finset.prod_const, Finset.card_range] at h₁
48- have h₂ : 0 < ∏ j ∈ Finset.Ioc i n, (cos (i * π / n) - cos (j * π / n)) := by
49- apply Finset.prod_pos
50- intro j hj
51- have : cos (j * π / n) < cos (i * π / n) := by
52- apply Real.strictAntiOn_cos (mem_Icc hn hi) (mem_Icc hn (by grind))
53- have : (i : ℝ) < j := by aesop
54- linear_combination (π / n) * this
55- linarith
79+ have h₂ : 0 < ∏ j ∈ Finset.Ioc i n, (chebyshevNode n i - chebyshevNode n j) :=
80+ Finset.prod_pos (fun j hj => sub_pos.mpr <|
81+ chebyshevNode_lt hi (Finset.mem_Ioc.mp hj).2 (Finset.mem_Ioc.mp hj).1 )
5682 have union : (Finset.range (n + 1 )).erase i = (Finset.range i) ∪ Finset.Ioc i n := by grind
5783 have disjoint : Disjoint (Finset.range i) (Finset.Ioc i n) := by grind [Finset.disjoint_iff_ne]
5884 rw [union, Finset.prod_union disjoint, ← mul_assoc]
5985 exact mul_pos h₁ h₂
6086
61- lemma leadingCoeff_formula {n : ℕ} (hn : n ≠ 0 ) {P : ℝ[X]} (hP : P.degree = n) :
62- ∃ (c : ℕ → ℝ),
63- (∀ i ∈ Finset.range (n + 1 ), 0 < c i) ∧
64- (∑ i ∈ Finset.range (n + 1 ), c i = 2 ^ (n - 1 )) ∧
65- (∑ i ∈ Finset.range (n + 1 ), (c i) * ((-1 ) ^ i * P.eval (cos (i * π / n))) = P.leadingCoeff) :=
66- by
67- have cos_inj : Set.InjOn (fun (i : ℕ) => cos (i * π / n)) (Finset.range (n + 1 )) := by
68- refine injOn_cos.comp ?_ (fun i hi => mem_Icc hn hi)
69- intro i hi j hj hij
70- suffices (i : ℝ) = j by norm_cast at this
71- linear_combination (norm := field) (n / π) * hij
72- have deg {Q : ℝ[X]} (hQ : Q.degree = n) : (Finset.range (n + 1 )).card = Q.degree + 1 := by
73- simp [Finset.card_range, hQ]
74- use fun i =>
75- ((-1 ) ^ i * ∏ j ∈ (Finset.range (n + 1 )).erase i, (cos (i * π / n) - cos (j * π / n)))⁻¹
76- refine ⟨?_, ⟨?_, ?_⟩⟩
77- · exact fun i hi => prod_pos hi |> inv_pos.mpr
78- · have := Lagrange.leadingCoeff_eq_sum cos_inj (deg (degree_T ℝ n))
79- rw [leadingCoeff_T, Int.natAbs_natCast] at this
80- rw [this]
81- congr! 1 with i hi
82- dsimp
83- have : ((n : ℤ) : ℝ) * (i * π / n) = (i : ℤ) * π := by norm_cast; field_simp
84- rw [T_real_cos, this, cos_int_mul_pi, zpow_natCast, mul_inv, ← div_eq_mul_inv, ← inv_pow,
85- inv_neg_one]
86- · rw [Lagrange.leadingCoeff_eq_sum cos_inj (deg hP)]
87- congr! 1 with i hi
88- field
89-
90- theorem bddAbove (P : ℝ[X]) : BddAbove { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } :=
91- have := P.continuous
92- have hcont : ContinuousOn (fun x => |P.eval x|) (Set.Icc (-1 ) 1 ) :=
93- Continuous.continuousOn (by continuity)
94- IsCompact.bddAbove_image isCompact_Icc hcont
95-
96- lemma P_eval_bound (P : ℝ[X]) (n i : ℕ) :
97- (-1 ) ^ i * P.eval (cos (i * π / n)) ≤ sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } := by
98- suffices |P.eval (cos (i * π / n))| ≤ sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } by
99- cases neg_one_pow_eq_or ℝ i with
100- | inl h => rw [h, one_mul]; exact (abs_le'.mp this).1
101- | inr h => rw [h, neg_one_mul]; exact (abs_le'.mp this).2
102- refine le_csSup (bddAbove P) (Set.mem_setOf.mpr ⟨cos (i * π / n), ⟨?_, rfl⟩⟩)
103- exact Set.mem_Icc.mpr <| abs_le.mp <| abs_cos_le_one _
104-
105- end Polynomial.Chebyshev
106-
107- @[expose] public section
108-
109- namespace Polynomial.Chebyshev
110-
111- open Polynomial Real
112-
113- theorem le_sup_abs_eval_of_monic {n : ℕ} (hn : n ≠ 0 )
114- {P : ℝ[X]} (Pdeg : P.degree = n) (Pmonic : P.Monic) :
115- 1 / 2 ^ (n - 1 ) ≤ sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } := by
116- suffices 1 ≤ 2 ^ (n - 1 ) * sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } by field_simp; assumption
117- obtain ⟨c, hpos, hsum, hform⟩ := leadingCoeff_formula hn Pdeg
118- calc 1 = P.leadingCoeff := Pmonic.symm
119- _ = ∑ i ∈ Finset.range (n + 1 ), (c i) * ((-1 )^i * P.eval (cos (i * π / n))) := hform.symm
120- _ ≤ ∑ i ∈ Finset.range (n + 1 ), (c i) * sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } := by
121- gcongr with i hi
122- · exact le_of_lt (hpos i hi)
123- · exact P_eval_bound P n i
124- _ = 2 ^ (n - 1 ) * sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } := by
125- rw [← Finset.sum_mul, hsum]
126-
127- theorem sup_abs_eval_eq_iff_of_monic {n : ℕ} (hn : n ≠ 0 ) (P : ℝ[X])
128- (Pdeg : P.degree = n) (Pmonic : P.Monic) :
129- sSup { |P.eval x| | x ∈ Set.Icc (-1 ) 1 } = 1 / 2 ^ (n - 1 ) ↔
130- P = (1 / 2 ^ (n - 1 ) : ℝ) • (T ℝ n) :=
131- by
132- constructor
133- case mp =>
134- intro hsSup
135- let extrema := (Finset.range (n + 1 )).image (fun (k : ℕ) => cos (k * π / n))
136- have card_extrema : extrema.card = n + 1 := by
137- rw [Finset.card_image_of_injOn, Finset.card_range]
138- apply injOn_cos.comp (by aesop)
139- intro k hk
140- apply Set.mem_Icc.mpr
141- constructor
142- · positivity
143- · field_simp
144- norm_cast
145- grind
146- apply eq_of_degrees_lt_of_eval_finset_eq extrema
147- · rw [Pdeg, card_extrema]; norm_cast; simp
148- · rw [smul_eq_C_mul, degree_C_mul (by positivity), degree_T, card_extrema]
149- norm_cast; simp
150- obtain ⟨c, hpos, hsum, hform⟩ := leadingCoeff_formula hn Pdeg
151- rw [Pmonic] at hform
152- let T' := (1 / 2 ^ (n - 1 ) : ℝ) • (T ℝ n)
153- have Tform (i : ℕ) :
154- (-1 ) ^ i * T'.eval (cos (i * π / n)) = 1 / 2 ^ (n - 1 ) := by
155- have : ((n : ℤ) : ℝ) * (i * π / n) = (i : ℤ) * π := by norm_cast; field_simp
156- rw [eval_smul, smul_eq_mul, T_real_cos, this, cos_int_mul_pi]
157- suffices ((-1 ) ^ i : ℝ) * (-1 ) ^ (i : ℤ) = 1 by grind
158- simp [← sq, ← pow_mul']
159- replace hform :
160- ∑ i ∈ Finset.range (n + 1 ), (c i) * ((-1 ) ^ i * P.eval (cos (i * π / n))) =
161- ∑ i ∈ Finset.range (n + 1 ), (c i) * ((-1 ) ^ i * T'.eval (cos (i * π / n))) := by
162- simp_rw [hform, Tform, ← Finset.sum_mul, hsum]
163- simp
164- replace hform := ge_of_eq hform
165- contrapose! hform
166- obtain ⟨θ, hθ, hPθ⟩ := hform
167- obtain ⟨i₀, hi₀, hi₀θ⟩ := Finset.mem_image.mp hθ
168- have h_le {i : ℕ} (hi : i ∈ Finset.range (n + 1 )) :
169- c i * ((-1 ) ^ i * P.eval (cos (i * π / n))) ≤
170- c i * ((-1 ) ^ i * T'.eval (cos (i * π / n))) := by
171- rw [Tform i, ← hsSup]
172- exact mul_le_mul_of_nonneg_left (P_eval_bound P n i) (le_of_lt (hpos i hi))
173- have h_lt₀ :
174- c i₀ * ((-1 ) ^ i₀ * P.eval (cos (i₀ * π / n))) <
175- c i₀ * ((-1 ) ^ i₀ * T'.eval (cos (i₀ * π / n))) := by
176- apply lt_of_le_of_ne (h_le hi₀)
177- rw [hi₀θ]
178- contrapose! hPθ
179- rw [← mul_assoc, ← mul_assoc] at hPθ
180- refine mul_left_cancel₀ ?_ hPθ
181- have := hpos i₀ hi₀
182- positivity
183- exact Finset.sum_lt_sum (fun i hi => h_le hi) ⟨i₀, hi₀, h_lt₀⟩
184- case mpr =>
185- intro hP
186- apply eq_of_le_of_ge
187- · refine csSup_le (by use |P.eval 1 |; grind) (fun x hx => ?_)
188- obtain ⟨θ, hθ, hx⟩ := Set.mem_setOf.mp hx
189- have := (abs_eval_T_real_le_one_iff (Int.ofNat_ne_zero.mpr hn) θ).mp (abs_le.mpr hθ)
190- aesop
191- · refine le_csSup (bddAbove P) ⟨1 , ⟨by grind, by aesop⟩⟩
87+ private lemma negOnePow_mul_negOnePow_mul_cancel {α β : ℝ} {i : ℕ} :
88+ ((-1 ) ^ i * α) * ((-1 ) ^ i * β) = α * β := calc
89+ _ = ((-1 ) ^ i * (-1 ) ^ i) * α * β := by ring
90+ _ = α * β := by simp [← mul_pow]
91+
92+ private lemma negOnePow_mul_le {α : ℝ} {i : ℕ} (hα : α ∈ Set.Icc (-1 ) 1 ) : (-1 ) ^ i * α ≤ 1 := by
93+ apply le_of_abs_le
94+ rw [abs_mul, abs_neg_one_pow, one_mul]
95+ exact abs_le.mpr hα
96+
97+ theorem apply_le_apply_T_real {n : ℕ} {param : ℝ[X] → ℝ} {c : ℕ → ℝ}
98+ (hparam : (P : ℝ[X]) → P.degree = n → param P = ∑ i ≤ n, P.eval (chebyshevNode n i) * (c i))
99+ (hcnonneg : ∀ i ≤ n, 0 ≤ (-1 ) ^ i * (c i))
100+ {P : ℝ[X]} (hPdeg : P.degree = n) (hPbnd : ∀ x ∈ Set.Icc (-1 ) 1 , P.eval x ∈ Set.Icc (-1 ) 1 ) :
101+ param P ≤ param (T ℝ n) := by
102+ wlog hn : n ≠ 0
103+ · push_neg at hn
104+ rw [hparam P hPdeg, hparam (T ℝ n) (degree_T ℝ n), hn, show Finset.Iic 0 = {0 } by rfl,
105+ Nat.cast_zero, T_zero, Finset.sum_singleton, Finset.sum_singleton, chebyshevNode_eq_one,
106+ eval_one]
107+ exact mul_le_mul_of_nonneg_right (hPbnd 1 (by simp) |> Set.mem_Icc.mp).2
108+ (le_of_le_of_eq (hcnonneg 0 n.zero_le) (one_mul _))
109+ calc
110+ param P = ∑ i ≤ n, P.eval (chebyshevNode n i) * (c i) := hparam P hPdeg
111+ _ ≤ ∑ i ≤ n, (T ℝ n).eval (chebyshevNode n i) * (c i) := by
112+ refine Finset.sum_le_sum (fun i hi => ?_)
113+ calc
114+ P.eval (chebyshevNode n i) * (c i) =
115+ ((-1 ) ^ i * P.eval (chebyshevNode n i)) * ((-1 ) ^ i * (c i)) :=
116+ negOnePow_mul_negOnePow_mul_cancel.symm
117+ _ ≤ 1 * ((-1 ) ^ i * (c i)) :=
118+ mul_le_mul_of_nonneg_right (negOnePow_mul_le (hPbnd _ chebyshevNode_mem_Icc))
119+ (hcnonneg i (Finset.mem_Iic.mp hi))
120+ _ = (T ℝ n).eval (chebyshevNode n i) * (c i) := by
121+ rw [eval_T_real_chebyshevNode hn, one_mul]
122+ _ = param (T ℝ n) := (hparam (T ℝ n) (degree_T ℝ n)).symm
123+
124+ theorem apply_eq_apply_T_real_iff {n : ℕ} {param : ℝ[X] → ℝ} {c : ℕ → ℝ}
125+ (hparam : (P : ℝ[X]) → P.degree = n → param P = ∑ i ≤ n, P.eval (chebyshevNode n i) * (c i))
126+ (hcpos : ∀ i ≤ n, 0 < (-1 ) ^ i * (c i))
127+ {P : ℝ[X]} (hPdeg : P.degree = n) (hPbnd : ∀ x ∈ Set.Icc (-1 ) 1 , P.eval x ∈ Set.Icc (-1 ) 1 ) :
128+ (param P = param (T ℝ n)) ↔ P = T ℝ n := by
129+ refine ⟨fun h => ?_, by intro h; rw [h]⟩
130+ wlog hn : n ≠ 0
131+ · push_neg at hn
132+ rw [hparam P hPdeg, hparam (T ℝ n) (degree_T ℝ n), hn, show Finset.Iic 0 = {0 } by rfl,
133+ Nat.cast_zero, T_zero, Finset.sum_singleton, Finset.sum_singleton, chebyshevNode_eq_one,
134+ eval_one, one_mul] at h
135+ rw [hn, Nat.cast_zero] at hPdeg
136+ rw [hn, Nat.cast_zero, T_zero]
137+ have eval_P_one : P.eval 1 = 1 :=
138+ (mul_eq_right₀ (ne_of_lt <| lt_of_lt_of_eq (hcpos 0 n.zero_le) (one_mul _)).symm).mp h
139+ rw [eq_C_of_degree_eq_zero hPdeg, eval_C] at eval_P_one
140+ rw [eq_C_of_degree_eq_zero hPdeg, eval_P_one, C_1]
141+ apply eq_of_degrees_lt_of_eval_finset_eq ((Finset.range (n + 1 )).image (chebyshevNode n ·))
142+ · rw [hPdeg, Nat.cast_lt, Finset.card_image_of_injOn (strictAntiOn_chebyshevNode n).injOn,
143+ Finset.card_range, Nat.lt_succ_iff]
144+ · rw [degree_T, Int.natAbs_natCast, Nat.cast_lt,
145+ Finset.card_image_of_injOn (strictAntiOn_chebyshevNode n).injOn,
146+ Finset.card_range, Nat.lt_succ_iff]
147+ rw [hparam P hPdeg, hparam (T ℝ n) (degree_T ℝ n)] at h
148+ replace h := ge_of_eq h
149+ contrapose! h
150+ obtain ⟨x, hx, hPx⟩ := h
151+ obtain ⟨i, hi, hix⟩ := Finset.mem_image.mp hx
152+ replace hi := Finset.mem_Iic.mpr (Finset.mem_range_succ_iff.mp hi)
153+ suffices ∑ i ≤ n, ((-1 ) ^ i * P.eval (chebyshevNode n i)) * ((-1 ) ^ i * c i) <
154+ ∑ i≤ n, ((-1 ) ^ i * (T ℝ n).eval (chebyshevNode n i)) * ((-1 ) ^ i * c i) by
155+ simp_rw [negOnePow_mul_negOnePow_mul_cancel] at this
156+ exact this
157+ have h_le {i : ℕ} (hi : i ∈ Finset.Iic n) :
158+ (-1 ) ^ i * P.eval (chebyshevNode n i) * ((-1 ) ^ i * c i) ≤
159+ (-1 ) ^ i * (T ℝ n).eval (chebyshevNode n i) * ((-1 ) ^ i * c i) := by
160+ refine mul_le_mul_of_nonneg_right ?_ (le_of_lt (hcpos i (Finset.mem_Iic.mp hi)))
161+ rw [eval_T_real_chebyshevNode hn, ← neg_pow', neg_neg, one_pow]
162+ exact negOnePow_mul_le (hPbnd _ chebyshevNode_mem_Icc)
163+ refine Finset.sum_lt_sum (fun i hi => h_le hi) ⟨i, hi, lt_of_le_of_ne (h_le hi) ?_⟩
164+ have := ne_of_lt (hcpos i (Finset.mem_Iic.mp hi))
165+ grind => ring
192166
193167end Polynomial.Chebyshev
0 commit comments