Zulip Chat Archive

Stream: new members

Topic: Chebyshev polynomial


Nick_adfor (Sep 15 2025 at 10:12):

I've trouble filling the following theorem, for the lemma I think useable cannot be fixed.

import Mathlib

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact U_eq  n

/-with errors
failed to infer structural recursion:
Cannot use parameter n:
  failed to eliminate recursive application
    U_eval_one m-/
lemma Chebyshev.U_eval_one (n : ) : (Chebyshev.U  n).eval 1 = (n + 1 : ) := by
  induction n with
  | zero => simp [Chebyshev.U]
  | succ n ih =>
    cases n with
    | zero => simp only [zero_add, Nat.cast_one, U_one, eval_mul, eval_ofNat, eval_X, mul_one]; ring_nf
    | succ m =>
      have : (Chebyshev.U  (m + 2)).eval 1 = 2 * 1 * (Chebyshev.U  (m + 1)).eval 1 - (Chebyshev.U  m).eval 1 := by
        simp [U_add_two, Polynomial.eval_sub, Polynomial.eval_mul, Polynomial.eval_X, Polynomial.eval_C]
      have : (Chebyshev.U  (m + 2)).eval 1 = 2 * (m + 2 : ) - (m + 1 : ) := by
        rw [this, Chebyshev.U_eval_one (m : )]
        ring_nf
        simp only [Polynomial.Chebyshev.U_eval_one, Int.cast_add, Int.cast_one, Int.cast_natCast]
        ring_nf
      ring_nf
      simp only [Nat.cast_add, Nat.cast_ofNat, Polynomial.Chebyshev.U_eval_one, Int.cast_add,
        Int.cast_ofNat, Int.cast_natCast]
      ring_nf

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
  (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction n with
  | zero => simp only [CharP.cast_eq_zero, U_zero, eval_one, pow_zero, zero_add, mul_one]
  | succ n ih =>
    cases n with
    | zero => simp only [zero_add, Nat.cast_one, U_one, eval_mul, eval_ofNat, eval_X, mul_neg,
      mul_one, pow_one, neg_mul, one_mul, neg_add_rev]; ring_nf

    | succ m =>
      have : (Chebyshev.U  (m + 2)).eval (-1)
            = 2 * (-1) * (Chebyshev.U  (m + 1)).eval (-1) - (Chebyshev.U  m).eval (-1) := by
        simp [U_add_two, Polynomial.eval_sub, Polynomial.eval_mul, Polynomial.eval_X, Polynomial.eval_C]
      have h0 : (Chebyshev.U  (m+2)).eval (-1) = Polynomial.eval (-1) (Chebyshev.U  (m+2)) := rfl
      have h1 : (Chebyshev.U  (m+1)).eval (-1) = Polynomial.eval (-1) (Chebyshev.U  (m+1)) := rfl
      have h2 : (Chebyshev.U  m).eval (-1) = Polynomial.eval (-1) (Chebyshev.U  m) := rfl
      have recurrence_eq : Polynomial.eval (-1) (Chebyshev.U  (m + 2)) =
                          2 * (-1) * Polynomial.eval (-1) (Chebyshev.U  (m + 1)) -
                          Polynomial.eval (-1) (Chebyshev.U  m) := by
        rw [ h0,  h1,  h2, this]
      have target_eq : (-1 : ) ^ (m + 2) * ((m + 2 : ) + 1 : ) = 2 * (-1) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        calc
          (-1 : ) ^ (m + 2) * ((m + 2 : ) + 1 : ) = (-1 : ) ^ m * (-1) ^ 2 * (m + 3 : ) := by
            ring_nf
            simp only [Nat.cast_add, Nat.cast_ofNat]
            ring_nf
          _ = (-1 : ) ^ m * 1 * (m + 3 : ) := by norm_num
          _ = 2 * (-1) * ((-1) * (-1 : ) ^ m * (m + 2)) - ((-1 : ) ^ m * (m + 1)) := by ring
          _ = 2 * (-1) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
            rw [show (-1 : ) * (-1 : ) ^ m = (-1 : ) ^ (m + 1) by ring]

      simp only [show (m + 1 + 1 : ) = m + 2 by omega]
      sorry

theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  -- Use the fact that Chebyshev polynomials have simple roots in (-1,1)

  have :  k : , k < n  ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval (Real.cos (Real.pi * (k + 1) / (n + 1)))  0 := by
    sorry  -- Would need to compute the derivative explicitly

  -- Show that x must be of the form cos(π*(k+1)/(n+1)) for some k
  have :  k : , k < n  x = Real.cos (Real.pi * (k + 1) / (n + 1)) := by
    set θ := Real.arccos (x/2) with 
    have hUθ := Chebyshev.U_real_cos θ n
    rw [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C,
        Polynomial.eval_X] at hx
    have hsinNθ : Real.sin ((n+1) * θ) = 0 := by
      sorry
    obtain k, hk := Real.sin_eq_zero_iff.1 hsinNθ
    sorry

  rcases this with k, _, hx
  rw [hx]
  exact this k k < n

Ilmārs Cīrulis (Sep 15 2025 at 10:29):

The web editor tells me that "Unknown identifier Chebyshev.U".

Ilmārs Cīrulis (Sep 15 2025 at 10:34):

Adding open Polynomial solves this problem.

Nick_adfor (Sep 15 2025 at 10:47):

There's a terrible thing: I write the code in v4.16.0. Lean 4 web might be v4.22.0. Some of U should be Chebyshev.U.

Nick_adfor (Sep 15 2025 at 10:48):

Now I fixed the second lemma, leaving the third and the theorem.

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp only [zero_add, Nat.cast_one, U_one, eval_mul, eval_ofNat, eval_X, mul_one]
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp only [Nat.cast_add, Nat.cast_ofNat, U_add_two, add_sub_cancel_right, sub_left_inj,
        mul_eq_mul_left_iff, mul_eq_zero, OfNat.ofNat_ne_zero, X_ne_zero, or_self, or_false,
        Nat.cast_one, U_eval_one, Int.cast_add, Int.cast_natCast, Int.cast_one] at this 

Nick_adfor (Sep 15 2025 at 14:19):

I'm wondering if there's some good way to finish realizing the theorem.

Snir Broshi (Sep 15 2025 at 22:15):

Can you please send a MWE that runs in Lean 4 Web correctly?
It's difficult to try to help without it

Nick_adfor (Sep 16 2025 at 00:15):

This part can work on lean 4 web (v4.24.0-rc1)

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp at this 

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have IH_m1 := IH (m + 1) hm2
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  -- Use the fact that Chebyshev polynomials have simple roots in (-1,1)

  have :  k : , k < n  ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval (Real.cos (Real.pi * (k + 1) / (n + 1)))  0 := by
    sorry  -- Would need to compute the derivative explicitly

  -- Show that x must be of the form cos(π*(k+1)/(n+1)) for some k
  have :  k : , k < n  x = Real.cos (Real.pi * (k + 1) / (n + 1)) := by
    set θ := Real.arccos (x/2) with 
    have hUθ := Chebyshev.U_real_cos θ n
    rw [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C,
        Polynomial.eval_X] at hx
    have hsinNθ : Real.sin ((n+1) * θ) = 0 := by
      sorry
    obtain k, hk := Real.sin_eq_zero_iff.1 hsinNθ
    sorry

  rcases this with k, _, hx
  rw [hx]
  exact this k k < n

Nick_adfor (Sep 16 2025 at 07:11):

Snir said:

Can you please send a MWE that runs in Lean 4 Web correctly?
It's difficult to try to help without it

Thank you for your attention. But now the main theorem haven't finished.

Nick_adfor (Sep 16 2025 at 07:12):

Ilmārs Cīrulis said:

Adding open Polynomial solves this problem.

More namespace is added in my new code to make it compatible for both v4.16.0 and v4.24.0-rc1(Lean 4 Web). But now the main theorem haven't finished.

Ilmārs Cīrulis (Sep 16 2025 at 10:04):

Thank you, will take a look today.

Ilmārs Cīrulis (Sep 16 2025 at 10:30):

Looks nontrivial to me, won't promise anything though.

Nick_adfor (Sep 16 2025 at 10:58):

Ilmārs Cīrulis said:

Looks nontrivial to me, won't promise anything though.

Terrible : (

Ilmārs Cīrulis (Sep 17 2025 at 21:44):

Did you manage to finish your proof?

Nick_adfor (Sep 18 2025 at 04:36):

Till today I just have a draft. I even do not find a good way to have all the lemma used in the proof of theorem.

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

macro "by_eval" : tactic => `(tactic| (
  apply Polynomial.funext
  intro x
  simp only [eval_sub, eval_add, eval_X, eval_C, eval_smul, eval_mul, eval_natCast, eval_pow, eval_neg, eval_ofNat, eval_one, eval_zero, smul_eq_mul]
  ring
))

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp at this 

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have IH_m1 := IH (m + 1) hm2
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  -- Use the fact that Chebyshev polynomials have simple roots in (-1,1)
  have comp_eval : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = (Chebyshev.U  n).eval ((1/2 : ) * x) := by
    simp [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C, Polynomial.eval_X]

  rw [comp_eval] at hx

  have :  (θ : ), x = 2 * Real.cos θ  Real.sin ((n + 1 : ) * θ) = 0 := by
    by_cases h : x^2  4
    · let θ := Real.arccos (x/2)
      have hθ1 : -1  x/2  x/2  1 := by
        constructor <;> sorry
      have hθ2 : Real.cos θ = x/2 := Real.cos_arccos hθ1.1 hθ1.2
      refine θ, by field_simp [hθ2], ?_⟩
      have := Chebyshev.U_real_cos θ n

      have : Real.sin θ  0 := by
        intro hsin
        have : x^2 = 4 := by
          have := Real.sin_sq_add_cos_sq θ
          rw [hsin, hθ2] at this
          nlinarith
        sorry
      field_simp [this] at hx
      sorry
    · exfalso
      have bound :  (n : ) (x : ), |x| > 1  (Chebyshev.U  n).eval x  0 := by
        intro k y hy
        induction' k using Nat.strong_induction_on with k IH
        rcases k with (rfl|rfl|m)
        · simp [Chebyshev.U_zero]
        · simp
          sorry
        · have rec_eq := Chebyshev.U_add_two  m
          simp [rec_eq, Polynomial.eval_sub, Polynomial.eval_mul, Polynomial.eval_X, Polynomial.eval_C] at *
          intro h
          have : 2 * y * (Chebyshev.U  (m + 1)).eval y = (Chebyshev.U  m).eval y := by sorry --seems wrong???
          have h1 : |2 * y * (Chebyshev.U  (m + 1)).eval y| > |(Chebyshev.U  m).eval y| := by
            have hy_pos : |y| > 0 := by
              have : y  0 := by
                intro hy0
                have : |y| = 0 := by rw [hy0]; norm_num
                linarith [hy]
              exact abs_pos.mpr this
            sorry
          sorry
      have : |x/2| > 1 := by
        rw [abs_div, abs_two]
        sorry
      sorry

  rcases this with θ, hx_eq, hsin
  rw [hx_eq]

  have deriv_comp : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                   Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    induction' n using Nat.strong_induction_on with k IH
    rcases k with (rfl|rfl|m)
    · simp
    · simp
      by_eval
    · simp only [Nat.cast_add, Nat.cast_one, one_div, add_sub_cancel_right]
      sorry

  rw [deriv_comp, Polynomial.eval_mul, Polynomial.eval_C]

  have hn_pos : (n + 1 : ) / 2  0 := by
    intro h
    have : n + 1 = 0 := by sorry
    omega

  refine mul_ne_zero (by exact hn_pos) ?_

  simp [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C, Polynomial.eval_X]

  have : Real.sin ((n + 1 : ) * θ) = 0 := hsin
  have :  (k : ), (n + 1 : ) * θ = π * k := by
    sorry

  rcases this with k, hk
  have : θ = (π * k) / (n + 1) := by
    field_simp
    linarith [hk]

  have U_eval : (Chebyshev.U  (n - 1)).eval (Real.cos (π * k / (n + 1))) =
               Real.sin (n * (π * k / (n + 1))) / Real.sin (π * k / (n + 1)) := by
    sorry

  sorry
  /-have : ∀ k : ℕ, k < n → ((Chebyshev.U ℝ n).comp (Polynomial.C (1/2) * X)).derivative.eval (Real.cos (Real.pi * (k + 1) / (n + 1))) ≠ 0 := by
    sorry  -- Would need to compute the derivative explicitly

  -- Show that x must be of the form cos(π*(k+1)/(n+1)) for some k
  have : ∃ k : ℕ, k < n ∧ x = Real.cos (Real.pi * (k + 1) / (n + 1)) := by
    set θ := Real.arccos (x/2) with hθ
    have hUθ := Chebyshev.U_real_cos θ n
    rw [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C,
        Polynomial.eval_X] at hx
    have hsinNθ : Real.sin ((n+1) * θ) = 0 := by
      sorry
    obtain ⟨k, hk⟩ := Real.sin_eq_zero_iff.1 hsinNθ
    sorry

  rcases this with ⟨k, _, hx⟩
  rw [hx]
  exact this k ‹k < n›-/

Nick_adfor (Sep 18 2025 at 04:39):

Ilmārs Cīrulis said:

Did you manage to finish your proof?

lemma Chebyshev.U_eval_neg_one and lemma Chebyshev.U_eval_one is not used. Maybe I do not remember the reason why I write these two lemma : (

Nick_adfor (Sep 18 2025 at 15:54):

Now I try to have one way (with sorry, containing two lemmas)

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

macro "by_eval" : tactic => `(tactic| (
  apply Polynomial.funext
  intro x
  simp only [eval_sub, eval_add, eval_X, eval_C, eval_smul, eval_mul, eval_natCast, eval_pow, eval_neg, eval_ofNat, eval_one, eval_zero, smul_eq_mul]
  ring
))

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp at this 

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have IH_m1 := IH (m + 1) hm2
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  have U_at_1 := Chebyshev_U_eval_one n
  have U_at_neg1 := Chebyshev.U_eval_neg_one n
  have endpoints_nonzero : n > 0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval 2  0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval (-2)  0 := by
    intro hn
    constructor
    · simp
      linarith [show (0 : ) < n + 1 from by exact_mod_cast Nat.succ_pos n]
    · simp
      exact Nat.cast_add_one_ne_zero n
  have root_in_open_interval : x^2 < 4 := by
    by_cases h : n = 0
    · subst h
      simp at hx 
    · have hn : n > 0 := Nat.pos_of_ne_zero h
      have h1, h2 := endpoints_nonzero hn
      by_contra! H
      have : x  -2  x  2 := by
        by_cases h : x  0
        · right
          nlinarith [H]
        · left
          have : x  0 := by linarith
          nlinarith [H]
      rcases this with (hx' | hx')
      · have : (1/2 : ) * x  -1 := by linarith
        have mono :  (y : ), y  -1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          rw [show y = -(-y) by ring] at hy 
          have : -y  1 := by linarith
          have U_neg : (Chebyshev.U  n).eval (-y) = (-1)^n * (Chebyshev.U  n).eval y := by
            induction' n with k IH
            · simp
            · rcases k with (rfl|k)
              · simp
              · have rec_eq := Chebyshev_U_recursion (k + 2) (by omega)
                rw [rec_eq]
                simp
                rw [show (-1 : ) ^ (k + 2) = (-1)^2 * (-1)^k by ring, show (-1 : )^2 = 1 by norm_num]
                ring_nf
                sorry
          have : (Chebyshev.U  n).eval 1 = n + 1 := U_at_1
          have pos : 0 < (Chebyshev.U  n).eval 1 := by sorry
          intro H
          sorry
        simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X] at hx
        sorry
      · have : (1/2 : ) * x  1 := by linarith
        have :  (y : ), y  1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          have pos : 0 < (Chebyshev.U  n).eval y := by
            induction' n with k IH
            · simp [Chebyshev.U_zero]
            · rcases k with (rfl|k)
              · simp [Chebyshev.U_one, hy]
                sorry
              · have rec_eq := Chebyshev_U_recursion (k + 2) (by omega)
                rw [rec_eq]
                simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat]
                sorry
          exact ne_of_gt pos
        simp at hx
        exact this ((2⁻¹ : ) * x) (by linarith) hx
  have :  (θ : ), x = 2 * Real.cos θ := by
    have : -1  x/2  x/2  1 := by
      constructor <;> sorry
    exact Real.arccos (x/2), by rw [Real.cos_arccos this.1 this.2]; ring

  rcases this with θ, hx_eq
  rw [hx_eq]

  have deriv_formula : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                     Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    sorry

  rw [deriv_formula, Polynomial.eval_mul, Polynomial.eval_C]

  refine mul_ne_zero (by norm_num; exact Nat.cast_add_one_ne_zero n) ?_
  simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X]

  have : (Chebyshev.U  (n - 1)).eval (cos θ)  0 := by
    intro H
    have U_prev_at_1 : (Chebyshev.U  (n - 1)).eval (1 : ) = n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev_U_eval_one (n - 1)
        simp at this 
    have U_prev_at_neg1 : (Chebyshev.U  (n - 1)).eval (-1 : ) = (-1)^(n - 1) * n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev.U_eval_neg_one (n - 1)
        simp at this 
        sorry
    sorry
  exact this

  /-have : ∀ k : ℕ, k < n → ((Chebyshev.U ℝ n).comp (Polynomial.C (1/2) * X)).derivative.eval (Real.cos (Real.pi * (k + 1) / (n + 1))) ≠ 0 := by
    sorry  -- Would need to compute the derivative explicitly

  -- Show that x must be of the form cos(π*(k+1)/(n+1)) for some k
  have : ∃ k : ℕ, k < n ∧ x = Real.cos (Real.pi * (k + 1) / (n + 1)) := by
    set θ := Real.arccos (x/2) with hθ
    have hUθ := Chebyshev.U_real_cos θ n
    rw [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C,
        Polynomial.eval_X] at hx
    have hsinNθ : Real.sin ((n+1) * θ) = 0 := by
      sorry
    obtain ⟨k, hk⟩ := Real.sin_eq_zero_iff.1 hsinNθ
    sorry

  rcases this with ⟨k, _, hx⟩
  rw [hx]
  exact this k ‹k < n›-/

Nick_adfor (Sep 18 2025 at 17:29):

Ilmārs Cīrulis said:

Did you manage to finish your proof?

You seem full of passion and able to offer some help, thank you so much!

Ilmārs Cīrulis (Sep 18 2025 at 17:40):

Are you talking about me? :sweat_smile: I'm no help currently because of lack of motivation.

Nick_adfor (Sep 18 2025 at 17:48):

Ilmārs Cīrulis said:

Are you talking about me? :sweat_smile: I'm no help currently because of lack of motivation.

Your reply seems to be pushing me to finish the proof. Doesn't that mean you already have a good way to complete it?

Ilmārs Cīrulis (Sep 18 2025 at 19:46):

Not exactly. But I'm glad you are progressing (it seems to me).

Hagb (Junyu Guo) (Sep 19 2025 at 08:14):

got a few sorries fixed, based on the last version posted

Nick_adfor (Sep 19 2025 at 15:37):

Line 121 lacks a sorry

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

macro "by_eval" : tactic => `(tactic| (
  apply Polynomial.funext
  intro x
  simp only [eval_sub, eval_add, eval_X, eval_C, eval_smul, eval_mul, eval_natCast, eval_pow, eval_neg, eval_ofNat, eval_one, eval_zero, smul_eq_mul]
  ring
))

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp at this 

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have IH_m1 := IH (m + 1) hm2
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  have U_at_1 := Chebyshev_U_eval_one n
  have U_at_neg1 := Chebyshev.U_eval_neg_one n
  have endpoints_nonzero : n > 0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval 2  0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval (-2)  0 := by
    intro hn
    constructor
    · simp
      linarith [show (0 : ) < n + 1 from by exact_mod_cast Nat.succ_pos n]
    · simp
      exact Nat.cast_add_one_ne_zero n
  have root_in_open_interval : x^2 < 4 := by
    by_cases h : n = 0
    · subst h
      simp at hx 
    · have hn : n > 0 := Nat.pos_of_ne_zero h
      have h1, h2 := endpoints_nonzero hn
      by_contra! H
      have : x  -2  x  2 := by
        by_cases h : x  0
        · right
          nlinarith [H]
        · left
          have : x  0 := by linarith
          nlinarith [H]
      rcases this with (hx' | hx')
      · have : (1/2 : ) * x  -1 := by linarith
        have mono :  (y : ), y  -1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          rw [show y = -(-y) by ring] at hy 
          have : -y  1 := by linarith
          have U_neg : (Chebyshev.U  n).eval (-y) = (-1)^n * (Chebyshev.U  n).eval y := by
            induction' n with k IH
            · simp
            · rcases k with (rfl|k)
              · simp
              · have rec_eq := Chebyshev_U_recursion (k + 2) (by omega)
                rw [rec_eq]
                simp
                rw [show (-1 : ) ^ (k + 2) = (-1)^2 * (-1)^k by ring, show (-1 : )^2 = 1 by norm_num]
                ring_nf
                sorry
          have : (Chebyshev.U  n).eval 1 = n + 1 := U_at_1
          have pos : 0 < (Chebyshev.U  n).eval 1 := by linarith
          intro H
          simp at H
          simp [H] at U_neg
          sorry
        simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X] at hx
        sorry
      · have : (1/2 : ) * x  1 := by linarith
        have :  (y : ), y  1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          have pos : 0 < (Chebyshev.U  n).eval y := by
            induction' n with k IH
            · simp [Chebyshev.U_zero]
            · rcases k with (rfl|k)
              · simp [Chebyshev.U_one, hy]
                linarith
              · have rec_eq := Chebyshev_U_recursion (k + 2) (by omega)
                rw [rec_eq]
                simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat]
                sorry
          exact ne_of_gt pos
        simp at hx
        exact this ((2⁻¹ : ) * x) (by linarith) hx
  have :  (θ : ), x = 2 * Real.cos θ := by
    have : -1  x/2  x/2  1 := by
      convert_to x * x < 2 * 2 at root_in_open_interval
      · ring
      · ring
      rw [ abs_lt_iff_mul_self_lt, abs_lt, abs_two] at root_in_open_interval
      split_ands <;> linarith
    exact Real.arccos (x/2), by rw [Real.cos_arccos this.1 this.2]; ring

  rcases this with θ, hx_eq
  rw [hx_eq]

  have deriv_formula : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                     Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    sorry

  rw [deriv_formula, Polynomial.eval_mul, Polynomial.eval_C]

  refine mul_ne_zero (by norm_num; exact Nat.cast_add_one_ne_zero n) ?_
  simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X]

  have : (Chebyshev.U  (n - 1)).eval (cos θ)  0 := by
    intro H
    have U_prev_at_1 : (Chebyshev.U  (n - 1)).eval (1 : ) = n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev_U_eval_one (n - 1)
        simp at this 
    have U_prev_at_neg1 : (Chebyshev.U  (n - 1)).eval (-1 : ) = (-1)^(n - 1) * n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev.U_eval_neg_one (n - 1)
        simp at this 
        have n_ge_one : n  1 := Nat.one_le_iff_ne_zero.mpr h
        simpa [n_ge_one]
    sorry
  exact this

  /-have : ∀ k : ℕ, k < n → ((Chebyshev.U ℝ n).comp (Polynomial.C (1/2) * X)).derivative.eval (Real.cos (Real.pi * (k + 1) / (n + 1))) ≠ 0 := by
    sorry  -- Would need to compute the derivative explicitly

  -- Show that x must be of the form cos(π*(k+1)/(n+1)) for some k
  have : ∃ k : ℕ, k < n ∧ x = Real.cos (Real.pi * (k + 1) / (n + 1)) := by
    set θ := Real.arccos (x/2) with hθ
    have hUθ := Chebyshev.U_real_cos θ n
    rw [Polynomial.eval_comp, Polynomial.eval_mul, Polynomial.eval_C,
        Polynomial.eval_X] at hx
    have hsinNθ : Real.sin ((n+1) * θ) = 0 := by
      sorry
    obtain ⟨k, hk⟩ := Real.sin_eq_zero_iff.1 hsinNθ
    sorry

  rcases this with ⟨k, _, hx⟩
  rw [hx]
  exact this k ‹k < n›-/

Nick_adfor (Sep 19 2025 at 15:39):

This part seems to need a tactic like by_eval?... But I'm not so familiar with the library about .comp.

  have deriv_formula : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                     Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    sorry

Jireh Loreaux (Sep 19 2025 at 17:09):

Here's a computation of the roots of the Chebyshev polynomials of the second kind and that they all have multiplicity one.

import Mathlib.Algebra.Polynomial.Roots
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Chebyshev
import Mathlib.Tactic.ComputeDegree

namespace Polynomial
namespace Chebyshev

variable (R : Type*) [CommRing R]

lemma degree_U_neg_one : (U R (-1)).degree =  := by
  simp [U_neg_one]

lemma degree_U_zero [Nontrivial R] : (U R 0).degree = 0 := by
  simp [U_zero]

lemma degree_U_ofNat [IsDomain R] (h : ringChar R  2) : (n : )  (U R n).degree = n
  | 0 => degree_U_zero R
  | 1 => by
    simp [U_one]
    have : degree (2 : R[X]) = 0 := by
      compute_degree
      exact Ring.two_ne_zero h
    simp [this]
  | n + 2 => by
    simp only [Nat.cast_add, Nat.cast_ofNat, U_add_two]
    have : degree (2 * X * U R (n + 1)) = n + 2 := by
      have h₂ : degree (2 * X : R[X]) = 1 := by
        compute_degree
        · exact Ring.two_ne_zero h
        · simp
      have this : (U R (n + 1)).degree = n + 1 := degree_U_ofNat h (n + 1)
      rw [degree_mul, this, add_comm, h₂]
      rfl
    rwa [degree_sub_eq_left_of_degree_lt]
    rw [this]
    rw [degree_U_ofNat h n]
    exact Order.lt_succ _ |>.trans <| Order.lt_succ _

open Real

lemma nodups (n : ) :
    (Multiset.map (fun k :   cos ((k + 1) * π / (n + 1))) (.range n)).Nodup := by
  refine (Finset.range n).nodup_map_iff_injOn.mpr ?_
  cases n with
  | zero => simp
  | succ n =>
    intro x hx y hy h
    simp at hx hy h
    replace h := injOn_cos ⟨?h₁, ?h₂ ⟨?h₃, ?h₄ h
    field_simp at h
    simpa using h
    case h₁ => positivity
    case h₃ => positivity
    all_goals
      rw [mul_div_right_comm]
      apply le_of_lt
      calc
        _ / (n + 1 + 1) * π < (n + 1 + 1) / (n + 1 + 1) * π := by gcongr; norm_cast
        _ = π := by field_simp

lemma roots_U_real (n : ) :
    (U  n).roots = Multiset.map (fun k :   cos ((k + 1) * π / (n + 1))) (.range n):= by
  cases n with
  | zero => simp
  | succ n =>
    have : (U  (n + 1)).roots.card  n + 1 := by
      convert card_roots' _
      exact Eq.symm <| natDegree_eq_of_degree_eq_some <| degree_U_ofNat  (by simp) (n + 1)
    apply Eq.symm <| Multiset.eq_of_le_of_card_le ?_ (by simpa)
    rw [Multiset.le_iff_count]
    intro x
    simp only [count_roots]
    rw [Multiset.count_eq_of_nodup (nodups (n + 1))]
    split_ifs with h
    · change 0 < _
      simp
      refine ne_zero_of_degree_gt (n := 0) ?_, ?_⟩
      · calc
          (0 : WithBot ) < n + 1 := by positivity
          _ = (U  (n + 1)).degree := degree_U_ofNat  (by simp) (n + 1) |>.symm
      · simp only [Nat.cast_add, Nat.cast_one, Multiset.mem_map, Multiset.mem_range] at h
        obtain k, hk, rfl := h
        have : 0 < sin ((k + 1) * π / (n + 1 + 1)) := by
          apply sin_pos_of_mem_Ioo by positivity, ?_⟩
          calc
            _ < (n + 1 + 1 : ) * π / (n + 1 + 1) := by gcongr; norm_cast
            _ = π := by field_simp
        rw [ mul_right_cancel_iff_of_pos this, zero_mul, U_real_cos]
        norm_cast
        field_simp
        exact sin_nat_mul_pi (k + 1)
    · simp

lemma rootMultiplicity_U_real {n : } {k : } (hk : k < n) :
    (U  n).rootMultiplicity (cos ((k + 1) * π / (n + 1))) = 1 := by
  rw [ count_roots, roots_U_real]
  refine Multiset.count_eq_one_of_mem (nodups n) ?_
  simpa using k, hk, rfl

end Chebyshev
end Polynomial

Jireh Loreaux (Sep 19 2025 at 17:11):

It's likely possible to simplify the above code a bit, but I think this is the natural argument. That is, "here are n distinct roots of this polynomial of degree n, so they all have multiplicity 1."

Nick_adfor (Sep 20 2025 at 03:29):

It seems that I should not choose derivative to finish the proof. (But later in Oct. 15th I find this part gives me more thoughts about developing API for scaleRoots.

Nick_adfor (Sep 20 2025 at 04:37):

Now this.

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

macro "by_eval" : tactic => `(tactic| (
  apply Polynomial.funext
  intro x
  simp only [eval_sub, eval_add, eval_X, eval_C, eval_smul, eval_mul, eval_natCast, eval_pow, eval_neg, eval_ofNat, eval_one, eval_zero, smul_eq_mul]
  ring
))

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n

lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp [Chebyshev.U_zero]
  · cases' n with n
    · simp
      ring_nf
    · have := Chebyshev_U_recursion (n + 2) (by omega)
      simp at this 

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have IH_m1 := IH (m + 1) hm2
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

lemma Chebyshev.U_neg (n : ) (x : ) :
    (U  n).eval (-x) = (-1 : )^n * (U  n).eval x := by
  induction' n using Nat.strong_induction_on with n ih
  rcases n with (rfl|rfl|m)
  · -- n = 0
    simp
  · -- n = 1
    simp
  · -- n = m + 2
    have eval_rec : (U  (m + 2)).eval (-x) =
                    2 * (-x) * (U  (m + 1)).eval (-x) - (U  m).eval (-x) := by
                      rw [ih m (Nat.le.step Nat.le.refl)]
                      simp
                      have h2 := ih m (by omega)
                      rw [h2]
    calc
      (U  (m + 2)).eval (-x)
          = 2 * (-x) * (U  (m + 1)).eval (-x) - (U  m).eval (-x) := by rw [eval_rec]
      _ = 2 * (-x) * ((-1 : )^(m + 1) * (U  (m + 1)).eval x)
            - ((-1 : )^m * (U  m).eval x) := by
            norm_num
            ring_nf
            rw [ih m (Nat.le.step Nat.le.refl)]
            ring_nf
            simp
            calc
              -(x * eval (-x) (U  (1 + m)) * 2)
                  = -(x * ((-1)^(m+1) * eval x (U  (m+1))) * 2) := by
                    congr 1
                    congr 1
                    congr 1
                    ring_nf
                    have h_eq : eval (-x) (U  (1 + m)) = -(eval x (U  (1 + m)) * (-1)^m) := by
                      calc
                        eval (-x) (U  (1 + m))
                            = eval (-x) (U  (m+1)) := by simp; ring_nf
                        _   = (-1)^(m+1) * eval x (U  (m+1)) := by rw [ih (m + 1) Nat.le.refl]
                        _   = (-1)^m * (-1) * eval x (U  (1+↑m)) := by ring_nf; simp
                        _   = -(eval x (U  (1+↑m)) * (-1)^m) := by ring
                    exact h_eq
              _ = x * eval x (U  (m+1)) * (-1)^m * 2 := by
                    rw [pow_succ]
                    ring
            rw [Int.add_comm]
      _ = (-1 : )^m * (2 * x * (U  (m + 1)).eval x - (U  m).eval x) := by ring
      _ = (-1 : )^m * (U  (m + 2)).eval x := by simp
      _ = (-1 : )^(m + 2) * (U  (m + 2)).eval x := by
        norm_num
        ring_nf
        exact (true_or (x * eval x (U  (1 + m)) * 2 - eval x (U  m) = 0)).mpr trivial


theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  have U_at_1 := Chebyshev_U_eval_one n
  have U_at_neg1 := Chebyshev.U_eval_neg_one n
  have endpoints_nonzero : n > 0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval 2  0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval (-2)  0 := by
    intro hn
    constructor
    · simp
      linarith [show (0 : ) < n + 1 from by exact_mod_cast Nat.succ_pos n]
    · simp
      exact Nat.cast_add_one_ne_zero n
  have root_in_open_interval : x^2 < 4 := by
    by_cases h : n = 0
    · subst h
      simp at hx 
    · have hn : n > 0 := Nat.pos_of_ne_zero h
      have h1, h2 := endpoints_nonzero hn
      by_contra! H
      have : x  -2  x  2 := by
        by_cases h : x  0
        · right
          nlinarith [H]
        · left
          have : x  0 := by linarith
          nlinarith [H]
      rcases this with (hx' | hx')
      · have : (1/2 : ) * x  -1 := by linarith
        have mono :  (y : ), y  -1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          rw [show y = -(-y) by ring] at hy 
          have : -y  1 := by linarith
          have U_neg : (Chebyshev.U  n).eval (-y) = (-1)^n * (Chebyshev.U  n).eval y := by exact Chebyshev.U_neg n y
          have : (Chebyshev.U  n).eval 1 = n + 1 := U_at_1
          have pos : 0 < (Chebyshev.U  n).eval 1 := by linarith
          intro H
          simp at H
          simp [H] at U_neg
          sorry
        simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X] at hx
        sorry
      · have : (1/2 : ) * x  1 := by linarith
        have :  (y : ), y  1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          have pos : 0 < (Chebyshev.U  n).eval y := by
            induction' n with k IH
            · simp [Chebyshev.U_zero]
            · rcases k with (rfl|k)
              · simp [Chebyshev.U_one, hy]
                linarith
              · have rec_eq := Chebyshev_U_recursion (k + 2) (by omega)
                rw [rec_eq]
                simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat]
                sorry
          exact ne_of_gt pos
        simp at hx
        exact this ((2⁻¹ : ) * x) (by linarith) hx
  have :  (θ : ), x = 2 * Real.cos θ := by
    have : -1  x/2  x/2  1 := by
      convert_to x * x < 2 * 2 at root_in_open_interval
      · ring
      · ring
      rw [ abs_lt_iff_mul_self_lt, abs_lt, abs_two] at root_in_open_interval
      split_ands <;> linarith
    exact Real.arccos (x/2), by rw [Real.cos_arccos this.1 this.2]; ring

  rcases this with θ, hx_eq
  rw [hx_eq]

  have deriv_formula : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                     Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    sorry

  rw [deriv_formula, Polynomial.eval_mul, Polynomial.eval_C]

  refine mul_ne_zero (by norm_num; exact Nat.cast_add_one_ne_zero n) ?_
  simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X]

  have : (Chebyshev.U  (n - 1)).eval (cos θ)  0 := by
    intro H
    have U_prev_at_1 : (Chebyshev.U  (n - 1)).eval (1 : ) = n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev_U_eval_one (n - 1)
        simp at this 
    have U_prev_at_neg1 : (Chebyshev.U  (n - 1)).eval (-1 : ) = (-1)^(n - 1) * n := by
      by_cases h : n = 0
      · subst h; simp [Chebyshev.U_zero]
      · have := Chebyshev.U_eval_neg_one (n - 1)
        simp at this 
        have n_ge_one : n  1 := Nat.one_le_iff_ne_zero.mpr h
        simpa [n_ge_one]
    sorry
  exact this

Nick_adfor (Sep 20 2025 at 04:39):

(deleted)

Nick_adfor (Sep 21 2025 at 15:04):

I extract some of the code as Chebyshev.U_pos_of_ge_one, leaving a lot of sorry.

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n


lemma Chebyshev.U_pos_of_ge_one {n : } {y : } (hy : 1  y) :
    0 < (U  n).eval y := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl | rfl | m)
  · simp
  · simp [U_one]
    linarith [hy]
  · have rec := Chebyshev_U_recursion (m+2) (by omega)
    simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec
    have IH_m   := IH m (by omega)
    have IH_m1  := IH (m + 1) (by omega)
    calc
      (U  (m+2)).eval y
          = (2 * y) * (U  (m+1)).eval y - (U  m).eval y := by
          rw [rec]
          simp
          ring_nf
          exact (true_or (y = 0)).mpr trivial
      _ > (U  (m+1)).eval y - (U  m).eval y := by
          have h2y : 2 * y  2 := by linarith
          simp
          ring_nf
          sorry
      _ > 0 := by
          have : (U  (m+1)).eval y > (U  m).eval y := by
            rcases m with _ | m
            · simp [U_zero, U_one, eval_X]
              linarith [hy]
            · have rec' := Chebyshev_U_recursion (m+1) (by simp; sorry)
              simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec'
              have IH_m := IH m (by omega)
              have IH_m_sub1 := IH (m-1) (by omega)
              have : (U  (m+1)).eval y = 2 * y * (U  m).eval y - (U  (m-1)).eval y := by
                rw [rec']
                simp [eval_sub, eval_mul, eval_X, eval_C]
                ring_nf
              have h2y : 2 * y  2 := by linarith
              have : (U  m).eval y > (U  (m-1)).eval y := by
                rcases m with _ | m
                · simp
                · have : (U  (m+1)).eval y > (U  m).eval y := by
                    have rec'' := Chebyshev_U_recursion (m+1) (by sorry)
                    simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec''
                    have IH_m := IH m (by omega)
                    have IH_m_sub1 := IH (m-1) (by omega)
                    have h2y : 2 * y > 1 := by linarith [hy]
                    sorry
                  simp
                  exact this
              sorry
          nlinarith

Nick_adfor (Sep 22 2025 at 02:09):

I cannot understand the topic : (

Nick_adfor (Sep 22 2025 at 02:10):

Now I extract some of the code as Chebyshev.U_pos_of_ge_one, leaving a lot of sorry (in my origin post)

Nick_adfor (Sep 22 2025 at 07:13):

Now the code writes like this:

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

set_option maxHeartbeats 1000000

lemma Chebyshev_U_recursion :
   n : , n  2  Chebyshev.U  n = 2 * X * Chebyshev.U  (n-1) - Chebyshev.U  (n-2) := by
  intro n hn
  exact Chebyshev.U_eq  n


lemma Chebyshev.U_pos_of_ge_one {n : } {y : } (hy : 1  y) :
    0 < (U  n).eval y := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl | rfl | m)
  · simp
  · simp [U_one]
    linarith [hy]
  · have rec := Chebyshev_U_recursion (m+2) (by omega)
    simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec
    have IH_m   := IH m (by omega)
    have IH_m1  := IH (m + 1) (by omega)
    calc
      (U  (m+2)).eval y
          = (2 * y) * (U  (m+1)).eval y - (U  m).eval y := by
          rw [rec]
          simp
          ring_nf
          exact (true_or (y = 0)).mpr trivial
      _ > (U  (m+1)).eval y - (U  m).eval y := by
          have h2y : 2 * y  2 := by linarith
          simp
          ring_nf
          sorry
      _ > 0 := by
          have : (U  (m+1)).eval y > (U  m).eval y := by
            rcases m with _ | m
            · simp [U_zero, U_one, eval_X]
              linarith [hy]
            · have rec' := Chebyshev_U_recursion (m+1) (by simp; sorry)
              simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec'
              have IH_m := IH m (by omega)
              have IH_m_sub1 := IH (m-1) (by omega)
              have : (U  (m+1)).eval y = 2 * y * (U  m).eval y - (U  (m-1)).eval y := by
                rw [rec']
                simp [eval_sub, eval_mul, eval_X, eval_C]
                ring_nf
              have h2y : 2 * y  2 := by linarith
              have : (U  m).eval y > (U  (m-1)).eval y := by
                rcases m with _ | m
                · simp
                · have : (U  (m+1)).eval y > (U  m).eval y := by
                    have rec'' := Chebyshev_U_recursion (m+1) (by sorry)
                    simp [eval_sub, eval_mul, eval_X, eval_C, eval_ofNat] at rec''
                    have IH_m := IH m (by omega)
                    have IH_m_sub1 := IH (m-1) (by omega)
                    have h2y : 2 * y > 1 := by linarith [hy]
                    sorry
                  simp
                  exact this
              sorry
          nlinarith


lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by
  induction' n with n IH
  · simp
  · cases' n with n
    · simp
      ring_nf
    · simp

/-- lemma: U_n(-1) = (-1)^n (n+1).-/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by
  induction' n using Nat.strong_induction_on with n IH
  rcases n with (rfl|rfl|m)
  · simp  -- n = 0
  · simp   -- n = 1
    ring_nf
  · -- n = m + 2, where m : ℕ
    have : m + 2 = (m + 1) + 1 := by omega
    rw [<-this]
    have hm1 : m < m + 2 := by omega
    have hm2 : m + 1 < m + 2 := by omega
    have rec_eq := Chebyshev.U_add_two  (m)
    simp only at rec_eq 
    have eval_rec_eq : (Chebyshev.U  (m + 2)).eval (-1) =
                      (2 * X * Chebyshev.U  (m + 1) - Chebyshev.U  m).eval (-1) := by
      rw [rec_eq]
    have cast_eq1 : (U  (m + 2) : Polynomial ) = U  ((m + 2) : ) := by simp
    have cast_eq2 : (U  (m + 1) : Polynomial ) = U  ((m + 1) : ) := by simp
    have cast_eq3 : (U  m : Polynomial ) = U  (m : ) := by simp
    rw [ cast_eq1]
    rw [rec_eq]
    simp only [eval_sub, eval_mul, eval_ofNat, eval_X]
    rw [IH m hm1]
    rw [cast_eq2]
    rw [IH (m + 1) hm2]
    calc
      2 * (-1 : ) * ((-1 : ) ^ (m + 1) * ((m + 1 : ) + 1 : )) - ((-1 : ) ^ m * (m + 1 : ))
        = 2 * (-1 : ) * ((-1 : ) ^ (m + 1) * (m + 2 : )) - ((-1 : ) ^ m * (m + 1 : )) := by
        simp
        ring_nf
      _ = 2 * (-1) * ((-1) * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * (1 * (-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = 2 * ((-1) ^ m * (m + 2)) - ((-1) ^ m * (m + 1)) := by ring
      _ = (-1) ^ m * (2*(m + 2) - (m + 1)) := by ring
      _ = (-1) ^ m * (m + 3) := by ring
      _ = (-1) ^ m * (-1)^2 * (m + 3) := by norm_num
      _ = (-1) ^ (m + 2) * (m + 3) := by ring
      _ = (-1 : ) ^ (m + 2) * (((m + 2 : ) : ) + 1) := by simp; ring_nf

lemma Chebyshev.U_neg (n : ) (x : ) :
    (U  n).eval (-x) = (-1 : )^n * (U  n).eval x := by
  induction' n using Nat.strong_induction_on with n ih
  rcases n with (rfl|rfl|m)
  · -- n = 0
    simp
  · -- n = 1
    simp
  · -- n = m + 2
    have eval_rec : (U  (m + 2)).eval (-x) =
                    2 * (-x) * (U  (m + 1)).eval (-x) - (U  m).eval (-x) := by
                      rw [ih m (Nat.le.step Nat.le.refl)]
                      simp
                      have h2 := ih m (by omega)
                      rw [h2]
    calc
      (U  (m + 2)).eval (-x)
          = 2 * (-x) * (U  (m + 1)).eval (-x) - (U  m).eval (-x) := by rw [eval_rec]
      _ = 2 * (-x) * ((-1 : )^(m + 1) * (U  (m + 1)).eval x)
            - ((-1 : )^m * (U  m).eval x) := by
            norm_num
            ring_nf
            rw [ih m (Nat.le.step Nat.le.refl)]
            ring_nf
            simp
            calc
              -(x * eval (-x) (U  (1 + m)) * 2)
                  = -(x * ((-1)^(m+1) * eval x (U  (m+1))) * 2) := by
                    congr 1
                    congr 1
                    congr 1
                    ring_nf
                    have h_eq : eval (-x) (U  (1 + m)) = -(eval x (U  (1 + m)) * (-1)^m) := by
                      calc
                        eval (-x) (U  (1 + m))
                            = eval (-x) (U  (m+1)) := by simp; ring_nf
                        _   = (-1)^(m+1) * eval x (U  (m+1)) := by rw [ih (m + 1) Nat.le.refl]
                        _   = (-1)^m * (-1) * eval x (U  (1+↑m)) := by ring_nf; simp
                        _   = -(eval x (U  (1+↑m)) * (-1)^m) := by ring
                    exact h_eq
              _ = x * eval x (U  (m+1)) * (-1)^m * 2 := by
                    rw [pow_succ]
                    ring
            rw [Int.add_comm]
      _ = (-1 : )^m * (2 * x * (U  (m + 1)).eval x - (U  m).eval x) := by ring
      _ = (-1 : )^m * (U  (m + 2)).eval x := by simp
      _ = (-1 : )^(m + 2) * (U  (m + 2)).eval x := by
        norm_num
        ring_nf
        exact (true_or (x * eval x (U  (1 + m)) * 2 - eval x (U  m) = 0)).mpr trivial




theorem Chebyshev_U_simple_roots (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by
  intro hx
  have U_at_1 := Chebyshev_U_eval_one n
  have U_at_neg1 := Chebyshev.U_eval_neg_one n
  have endpoints_nonzero : n > 0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval 2  0 
      ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval (-2)  0 := by
    intro hn
    constructor
    · simp
      linarith [show (0 : ) < n + 1 from by exact_mod_cast Nat.succ_pos n]
    · simp
      exact Nat.cast_add_one_ne_zero n
  have root_in_open_interval : x^2 < 4 := by
    by_cases h : n = 0
    · subst h
      simp at hx 
    · have hn : n > 0 := Nat.pos_of_ne_zero h
      have h1, h2 := endpoints_nonzero hn
      by_contra! H
      have : x  -2  x  2 := by
        by_cases h : x  0
        · right
          nlinarith [H]
        · left
          have : x  0 := by linarith
          nlinarith [H]
      rcases this with (hx' | hx')
      · sorry

      · have :  (y : ), y  1  (Chebyshev.U  n).eval y  0 := by
          intro y hy
          have pos : 0 < (Chebyshev.U  n).eval y := by exact Chebyshev.U_pos_of_ge_one hy
          exact ne_of_gt pos
        simp at hx
        exact this ((2⁻¹ : ) * x) (by linarith) hx
  have :  (θ : ), x = 2 * Real.cos θ := by
    have : -1  x/2  x/2  1 := by
      convert_to x * x < 2 * 2 at root_in_open_interval
      · ring
      · ring
      rw [ abs_lt_iff_mul_self_lt, abs_lt, abs_two] at root_in_open_interval
      split_ands <;> linarith
    exact Real.arccos (x/2), by rw [Real.cos_arccos this.1 this.2]; ring

  rcases this with θ, hx_eq
  rw [hx_eq]

  have deriv_formula : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative =
                     Polynomial.C ((n + 1 : ) / 2) * (Chebyshev.U  (n - 1)).comp (Polynomial.C (1/2) * X) := by
    sorry

  rw [deriv_formula, Polynomial.eval_mul, Polynomial.eval_C]

  refine mul_ne_zero (by norm_num; exact Nat.cast_add_one_ne_zero n) ?_
  simp [Polynomial.eval_comp, eval_mul, eval_C, eval_X]

  have : (Chebyshev.U  (n - 1)).eval (cos θ)  0 := by
    intro H
    have U_prev_at_1 : (Chebyshev.U  (n - 1)).eval (1 : ) = n := by
      by_cases h : n = 0
      · subst h; simp
      · have := Chebyshev_U_eval_one (n - 1)
        simp at this 
    have U_prev_at_neg1 : (Chebyshev.U  (n - 1)).eval (-1 : ) = (-1)^(n - 1) * n := by
      by_cases h : n = 0
      · subst h; simp
      · have := Chebyshev.U_eval_neg_one (n - 1)
        simp at this 
        have n_ge_one : n  1 := Nat.one_le_iff_ne_zero.mpr h
        simpa [n_ge_one]
    have h₀ : (Chebyshev.U  n).eval (cos θ) = 0 := by
      simp [hx_eq] at hx
      exact hx
    have h₁ : (Chebyshev.U  (n - 1)).eval (cos θ) = 0 := H
    have :  m, m  n  (Chebyshev.U  (n - m)).eval (cos θ) = 0 := by sorry
  exact this

--#lint docBlameThm

Notification Bot (Sep 22 2025 at 09:21):

3 messages were moved here from #general > Computable polynomial representation based on sorted list by Eric Wieser.

Eric Wieser (Sep 22 2025 at 09:21):

@Nick_adfor , please don't double post. If you want to draw attention in one thread to a problem you have in another, I recommend linking between the threads instead

Nick_adfor (Sep 22 2025 at 09:34):

Eric Wieser said:

Nick_adfor , please don't double post. If you want to draw attention in one thread to a problem you have in another, I recommend linking between the threads instead

@Eric Wieser , please do not remove code from the post. Some of them are from my historical versions. How do I version back if you remove them?

Eric Wieser (Sep 22 2025 at 09:36):

I did not remove anything, I just moved your messages between the threads:

Notification Bot said:

3 messages were moved here from #general > Computable polynomial representation based on sorted list by Eric Wieser.

Nick_adfor (Oct 13 2025 at 12:23):

I've finished the part Chebyshev_U_scaled_deriv_ne_zero(417 lines) so I just admit here. For the main theorem, I want to use Chebyshev_U_scaled_deriv_ne_zero to prove the scaled polynomial is separable, then transfer this property to the original Chebyshev polynomial via root scaling relationship.

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

/-- Derivative at roots of scaled Chebyshev polynomials is nonzero.-/
lemma Chebyshev_U_scaled_deriv_ne_zero (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by admit
-- I've finished the `admit` part, but it's very long (417 lines). So I just `admit` here.

/-- All roots of Chebyshev polynomials of the second kind are simple. -/
theorem Chebyshev_U_roots_simple (n : ) :
    (Polynomial.roots (Chebyshev.U  n)).Nodup := by
  have root_scaling : Polynomial.roots (Chebyshev.U  n) =
         (Polynomial.roots ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X))).map (· * 2) := by
    sorry
  rw [root_scaling]
  apply Multiset.Nodup.map
  · -- Multiplication by 2 is injective
    intro a b h
    sorry
  · -- Scaled polynomial has simple roots
    have h_separable : Polynomial.Separable ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)) := by
      rw [Polynomial.separable_iff_derivative_ne_zero]
      intro h
      -- If derivative is zero polynomial, find contradiction
      by_cases hn : n = 0
      · subst hn; sorry
      · -- Chebyshev polynomials have roots (e.g., use intermediate value theorem)
        have :  x : , ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 := by
          sorry
        rcases this with x, hx
        have := Chebyshev_U_scaled_deriv_ne_zero n x hx
        rw [h] at this
        simp at this
      have irreducible : Irreducible ((U  n).comp (Polynomial.C (1 / 2) * X)) := by sorry
      exact irreducible
    exact nodup_roots h_separable

Jireh Loreaux (Oct 13 2025 at 13:49):

Nick, I already proved this for you in another thread? See #new members > Chebyshev polynomial @ 💬 . Why are you continuing with this exactly?

Nick_adfor (Oct 13 2025 at 14:08):

This is classic programmer humor :-) I'm basically reinventing the wheel, but all in the name of creating more APIs.

Notification Bot (Oct 13 2025 at 14:08):

3 messages were moved here from #mathlib4 > Prove that Chebyshev_U_roots_simple by Kevin Buzzard.

Jireh Loreaux (Oct 13 2025 at 16:57):

Nick, I don't really consider it humorous that you're asking people to duplicate work that's already been done, especially without reference to the prior work, as this can influence whether someone wants to put forth the effort to help you or not. Notice that Kevin merged the threads. I've noticed you have several threads about Chebyshev polynomials floating around, and some of those were merged as well. It's generally in bad taste on Zulip to ask virtually the same question multiple times in different places.

If you want to create more API, go for it, but that doesn't really seem to be what you're doing here. From what I can tell, you're proving very specific facts about Chebyshev polynomials, and you're not choosing to use the API that does already exist.

Nick_adfor (Oct 13 2025 at 17:04):

Okay Jireh, your instant help is appreciated. But I have to say that my whole work is to solve a whole problem (long lemmas and theorems), so check all API is really needed. The problem is as follows:

Problem 1: Prove the recurrence relation for the characteristic polynomial
Let the matrix A(n) be an n × n real matrix with elements defined as:
A(n)ij =
0, if | i - j | > 1
1, if | i - j | = 1
0, otherwise
This means A(n) is a tridiagonal matrix with 0 on the main diagonal and 1 on the sub- and super-diagonals.
Let pₙ(X) = charpoly(A(n)) = det(XIₙ - A(n)). We need to prove:
pₙ(X) = X ⋅ pₙ₋₁(X) - pₙ₋₂(X), for n ≥ 2

Problem 2: Prove that all roots of the second kind Chebyshev polynomial Uₙ(x) are real and simple

Problem 3: Prove that all eigenvalues of matrix A(n) are real and distinct

Nick_adfor (Oct 13 2025 at 17:05):

As you can see here, now we are working on problem 2 and you give a splendid proof. But I should have good way to use problem 2 to finish proving problem 3. So I do need some work on scaled Chebyshev polynomial. In the process of Chebyshev_U_scaled_deriv_ne_zero, I leave some lemma (I may call them API) suitable for scaled ones.

Jireh Loreaux (Oct 13 2025 at 19:39):

So for this, you shouldn't be asking about Chebyshev polynomials. You should ask the more general question: if p : R[X] is a polynomial, how are its roots related to those of p.comp (C a * X) for a : R? And in your case R := ℝ and a := 1 / 2.

The approach I think you should likely take here is to develop API for docs#Polynomial.scaleRoots. It is not quite the case that the characteristic polynomial of your matrix is a scaleRoots version of the Chebyshev polynomial, but it should be after multiplying by a suitable constant (in particular, I think the characteristic polynomial of your matrix is C (2 ^ (-n : ℤ)) * ((U ℝ n).scaleRoots 2)). So you should prove a fact relating the docs#Polynomial.rootMultiplicity of the scaled root of docs#Polynomial.scaleRoots to the root multiplicity of the original root of the polynomial. This should be possible using docs#IsUnit.scaleRoots_dvd_iff and docs#Polynomial.le_rootMultiplicity_iff and docs#Polynomial.rootMultiplicity_le_iff. From there you can get the appropriate statement relating the roots of the two polynomials.

Jireh Loreaux (Oct 13 2025 at 19:43):

Basically, if p is a polynomial of degree n in R[X] and a : Rˣ, then p.comp (C (a⁻¹) * X) = C (a ^ (-n : ℤ)) * p.scaleRoots a.

Nick_adfor (Oct 14 2025 at 04:50):

This would be a great extension, translating my specific situations into abstract ones.

Jireh Loreaux (Oct 14 2025 at 07:05):

Glad you agree. I suggest you write it.

Nick_adfor (Oct 15 2025 at 01:05):

These are the finished part. admit means that I have finished them. Now I try to get some of them expanded, also develop API for scaleRoots.

import Mathlib

open Polynomial Real
open Polynomial
open Chebyshev

/-- Non-vanishing at endpoints for scaled Chebyshev polynomials.
For any natural number n, Uₙ(1) ≠ 0 and Uₙ(-1) ≠ 0. -/
lemma endpoints_nonzero (n : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval 2  0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval (-2)  0 := by admit

/-- Parity property of Chebyshev polynomials.
For any natural number n and real number x, Uₙ(-x) = (-1)ⁿUₙ(x). -/
lemma Chebyshev.U_neg (n : ) (x : ) :
    (U  n).eval (-x) = (-1 : ) ^ n * (U  n).eval x := by admit

/-- Cosine representation theorem for real numbers in a symmetric interval.
For any a > 0 and real number x with |x| ≤ a, there exists θ such that x = a cos θ. -/
lemma exists_cos_representation_general (x a : ) (ha : a > 0) (h : |x|  a) :
     (θ : ), x = a * Real.cos θ := by
  -- Show that x / a is in the domain of arccos [-1, 1]
  have bound : -1  x / a  x / a  1 := by admit

/-- Cosine representation theorem for real numbers in the interval (-2, 2).-/
lemma exists_cos_representation (x : ) (h : x ^ 2 < 4) :  (θ : ), x = 2 * Real.cos θ := by admit

/-- Positivity of Chebyshev polynomials of the second kind on [1, ∞).-/
lemma Chebyshev.U_pos_of_ge_one {n : } {y : } (hy : 1  y) :
    0 < (U  n).eval y := by admit

/-- Derivative of the composition U_n(cos θ) using the chain rule.-/
lemma deriv_chebyshev_U_compose_cos (n : ) (θ : ) :
    deriv (fun t => (Chebyshev.U  n).eval (Real.cos t)) θ =
    (Polynomial.derivative (Chebyshev.U  n)).eval (Real.cos θ) * (-Real.sin θ) := by admit

/-- Roots of scaled Chebyshev polynomials lie in the open interval (-2, 2). -/
lemma root_in_open_interval (n : ) (x : )
    (hx : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0) :
    x ^ 2 < 4 := by admit

/-- Evaluation of Chebyshev polynomials at x = 1.
For any natural number n, Uₙ(1) = n + 1. -/
lemma Chebyshev_U_eval_one (n : ) : (Chebyshev.U  n).eval (1 : ) = (n + 1 : ) := by admit

/-- Evaluation of Chebyshev polynomials at x = -1.
For any natural number n, Uₙ(-1) = (-1)ⁿ(n + 1). -/
lemma Chebyshev.U_eval_neg_one (n : ) :
    (Chebyshev.U  n).eval (-1) = (-1 : ) ^ n * (n + 1 : ) := by admit

/-- Analysis of roots of scaled Chebyshev polynomials of the second kind.

If `((U ℝ n).comp (C (1/2) * X)).eval x = 0`, then there exists an angle `θ` such that:
- `x = 2 * cos θ` (cosine representation)
- `Uₙ(cos θ) = 0` (Chebyshev polynomial vanishes at cos θ)
- `sin((n+1)θ) = 0` (trigonometric identity consequence)
- `sin θ ≠ 0` (non-degeneracy condition)
- The derivative satisfies a specific formula:
  `Uₙ'(cos θ) = -(n+1)cos((n+1)θ)/sin²θ`

This provides a complete characterization of roots in terms of trigonometric functions. -/
lemma chebyshev_root_analysis (n : ) (x : )
    (hx : ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0) :
     (θ : ),
      x = 2 * Real.cos θ 
      (Chebyshev.U  n).eval (Real.cos θ) = 0 
      Real.sin ((n + 1 : ) * θ) = 0 
      Real.sin θ  0 
      (Polynomial.derivative (Chebyshev.U  n)).eval (Real.cos θ) =
      - (n + 1 : ) * Real.cos ((n + 1) * θ) / (Real.sin θ) ^ 2 := by admit

/-- Derivative at roots of scaled Chebyshev polynomials is nonzero.-/
theorem Chebyshev_U_scaled_deriv_ne_zero (n : ) (x : ) :
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).eval x = 0 
    ((Chebyshev.U  n).comp (Polynomial.C (1/2) * X)).derivative.eval x  0 := by admit

Nick_adfor (Oct 15 2025 at 01:20):

Jireh Loreaux said:

It's likely possible to simplify the above code a bit, but I think this is the natural argument. That is, "here are n distinct roots of this polynomial of degree n, so they all have multiplicity 1."

I’m going to simplify this later.

Nick_adfor (Oct 16 2025 at 03:22):

Jireh Loreaux said:

Nick, I already proved this for you in another thread? See #new members > Chebyshev polynomial @ 💬 . Why are you continuing with this exactly?

Sir, I spent some time searching for my memory of the reason why I do not use your method. It is that in your code

lemma nodups (n : ) :
    (Multiset.map (fun k :   cos ((k + 1) * π / (n + 1))) (.range n)).Nodup := by
  refine (Finset.range n).nodup_map_iff_injOn.mpr ?_

This part cannot work on v4.16.0. It gives an error

function expected at
  Finset.nodup_map_iff_injOn
term has type
  (Multiset.map ?m.32354 (Finset.val ?m.32355)).Nodup  Set.InjOn ?m.32354 ↑?m.32355Lean 4
Finset.nodup_map_iff_injOn.{u_1, u_2} {α : Type u_1} {β : Type u_2} {f : α  β} {s : Finset α} :
  (Multiset.map f s.val).Nodup  Set.InjOn f s

which I cannot find how to fix. It seems that the error is not about lacking a theorem in the latest version, but about some auto proof.

Ruben Van de Velde (Oct 16 2025 at 06:01):

Why are you using 4.16?

Nick_adfor (Oct 16 2025 at 07:35):

4.16 is the version of leansearch.net so to build this search engine every code must be able to run in 4.16 (rather than the latest version)

Kenny Lau (Oct 16 2025 at 08:50):

why do you have to use leansearch

Nick_adfor (Oct 16 2025 at 08:59):

I am in the team of leansearch.net

Nick_adfor (Oct 16 2025 at 09:00):

As this is a year-long (and potentially longer) team project, we need to standardize on a version for training the search engine to ensure the entire team is aligned.

Nick_adfor (Oct 16 2025 at 09:11):

This means that as more contributors build upon Mathlib beyond v4.16.0, the wider the compatibility gap with our search engine grows. This, in turn, reduces the engine's ability to make newer code discoverable. Striking a balance is challenging, which is why assistance from communities like Zulip becomes vital. However, a key problem remains: porting code from the latest version back to our old engine base often requires significant additional work.

Nick_adfor (Oct 16 2025 at 09:13):

Like now I really have problem with Jireh Loreaux's nodup

Kevin Buzzard (Oct 16 2025 at 09:26):

Thanks a lot for explaining the background, it makes things a lot clearer! I am still a bit confused about the relationship between LeanSearch (a natural language search engine) and your goal to prove new theorems about Chebyshev polynomials (which seems to have nothing to do with search engines per se).

I think that in practice you are going to find it quite difficult to find people in this community who are going to answer questions of the form "how do I get this working in v4.16".

Nick_adfor (Oct 16 2025 at 09:44):

It is a great honor, Professor. This problem on Chebyshev polynomials is being used as a dataset to enhance the LeanSearch engine's understanding of version v4.16.0.

I have sought help from the Zulip community regarding these problems, while being fully aware that the solutions provided there are likely based on much newer versions rather than v4.16.0. Whether the code runs successfully is somewhat a matter of luck, and subsequent adjustments are often necessary. That said, I do need to address the question raised here: "If the proof of this theorem is already complete, why write another version?" In reality, the final refinements will still be carried out by me independently — yet every bit of assistance is warmly welcomed and deeply appreciated.

Jireh Loreaux (Oct 16 2025 at 12:01):

Tip: don't backport code to train on 4.16. Retrain the existing model on the current version. If you don't, your results will be lost to oblivion and won't be interesting anyway as they will already be nine months (or much more!) out of date. If you can't update the model every few months quickly and efficiently, then that's the first problem to solve.

Jireh Loreaux (Oct 16 2025 at 12:04):

Kevin Buzzard said:

I think that in practice you are going to find it quite difficult to find people in this community who are going to answer questions of the form "how do I get this working in v4.16".

Indeed, I don't have time to waste backporting code to train AI, so I'll be disengaging now.

Nick_adfor (Oct 16 2025 at 12:30):

Jireh Loreaux said:

Tip: don't backport code to train on 4.16. Retrain the existing model on the current version.

We are facing a time constraint. The fact that a perfect search engine remains elusive nine months after the release of v4.16.0 suggests that we may have to treat the development of Mathlib and the search engine as mutually exclusive priorities.

Nick_adfor (Oct 16 2025 at 12:39):

But in fact if familiar with both the latest and the old version, we can write code suitable for both the versions. Its just different technique team doing different things and there's nothing terrible.

Kim Morrison (Oct 25 2025 at 23:04):

I think the lesson from this is that you need a fundamental rethink of your search engine design --- i.e. the lesson is that that current design is a failure, not that you should be spending effort backporting material.

Kim Morrison (Oct 25 2025 at 23:07):

And I'd request please not dragging others into the time-wasting activity of backporting to ancient versions. (i.e. by asking for assistance for such...)

Nick_adfor (Oct 26 2025 at 03:14):

Kim Morrison said:

And I'd request please not dragging others into the time-wasting activity of backporting to ancient versions. (i.e. by asking for assistance for such...)

I'll incorporate further updates based on the suggestions here. Yet I must emphasize that all the questions and answers are built on the latest version. If anything isn't compatible with an earlier one, I'll handle the extra work myself. Honestly, these are just some leftover tasks from earlier. Going forward, these theorem about Chebyshev Polynomials will be updated with more integrated tactics by myself into Mathlib, using a much more effective approach.


Last updated: Dec 20 2025 at 21:32 UTC