Zulip Chat Archive

Stream: new members

Topic: Prove using rational root theorem


Nick_adfor (Aug 13 2025 at 18:18):

Now I want to prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.

I leave some sorry that I don't know how to fill in.

import Mathlib

open Matrix Polynomial
/-
Rational eigenvector problem for integer matrices

We prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.
The main tools are the characteristic polynomial and the rational root theorem.
-/

/-- Map an integer matrix A to a rational matrix -/
def Aq {n : } (A : Matrix (Fin n) (Fin n) ) : Matrix (Fin n) (Fin n)  :=
  A.map (Int.castRingHom ) -- Use the ring homomorphism to map each element from ℤ to ℚ

/--
Key lemma: eigenvalue condition translated into a polynomial root
-/
lemma matrix_root_iff_charpoly_root
  {n : } (A : Matrix (Fin n) (Fin n) ) (r : )
  (X : Fin n  ) (hX : X  0) :
  (Aq A).mulVec X = r  X  aeval r (charpoly (Aq A)) = 0 := by
  intro h
  -- Step 1: Show (r•I - A)X = 0
  have hker : (r  (1 : Matrix _ _ ) - Aq A).mulVec X = 0 := by
    rw [Matrix.sub_mulVec, Matrix.smul_mulVec_assoc, one_mulVec, h, sub_self]
  -- Step 2: Non-zero solution implies determinant is 0
  have hdet : (r  (1 : Matrix _ _ ) - Aq A).det = 0 := by
    refine (Matrix.exists_mulVec_eq_zero_iff_aux).mp X, hX, hker
  -- Step 3: Show det(r•I - A) = charpoly(A)(r)
  have : (charpoly (Aq A)).eval r = (r  (1 : Matrix (Fin n) (Fin n) ) - Aq A).det := by
    rw [charpoly, charmatrix, eval_det, scalar_apply, RingHom.mapMatrix_apply, map_sub]
    simp only [scalar_apply, matPolyEquiv_diagonal_X, matPolyEquiv_map_C, eval_sub, eval_X, eval_C, smul_one_eq_diagonal]
  -- Final conclusion
  rw [ this] at hdet
  exact hdet

/-!
Main theorem: only trivial solution exists
-/
theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by
  -- Proof by contradiction: assume there exists a non-zero solution X ≠ 0
  intro X h
  by_contra hX
  push_neg at hX

  -- Define key objects
  let Aℚ := Aq A                    -- Rational matrix
  let r :  := q / p                -- Eigenvalue q/p
  let f : Polynomial  := charpoly Aℚ -- Characteristic polynomial

  -- Step 1: Show r is a root of f
  have h_root : aeval r f = 0 :=
    matrix_root_iff_charpoly_root A r X hX h

  -- Step 2: Relate integer coefficients to rational characteristic polynomial
  have charpoly_map : f = Polynomial.map (Int.castRingHom ) (charpoly A) := by
    simp only [ charpoly_map, Int.coe_castRingHom]
    exact rfl

  -- Step 3: Show leading coefficient is 1
  have leading_one : f.leadingCoeff = 1 := by
    rw [MonCat.one_of,  Monic.def]
    exact charpoly_monic Aℚ

  -- Step 4: Extract numerator and denominator
  let d := r.den  -- Denominator (since r = q/p is reduced, d = p.natAbs)

  -- Step 5: Apply the rational root theorem
  have den_dvd_1 : d = 1 := by
    have A_leading_one : A.charpoly.leadingCoeff = 1 := by
      have := charpoly_monic A
      exact this
    have leading_one' : f.leadingCoeff = 1 := leading_one
    rw [charpoly_map] at leading_one
    have leading_coeff_map : f.leadingCoeff = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [charpoly_map, leading_one]
      exact Rat.ext (id (Eq.symm A_leading_one)) rfl
    have leading_coeff_map' : 1 = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [ leading_coeff_map,  leading_one, charpoly_map]
    have h_root_int : aeval r (charpoly A) = 0 := by
      sorry
    have dvd1 : ((IsFractionRing.den  r) : )  (charpoly A).leadingCoeff := by
      exact den_dvd_of_is_root h_root_int
    rw [A_leading_one] at dvd1
    have abs1 : ((IsFractionRing.den  r : )).natAbs = 1 := by
      have hu : IsUnit (IsFractionRing.den  r : ) :=
        isUnit_of_dvd_one dvd1
      exact Int.natAbs_of_isUnit hu
    sorry
  have r_int : r.den = 1 := den_dvd_1
  have r_eq_int : r = r.num := by
    rw [Rat.coe_int_num_of_den_eq_one den_dvd_1]
  -- Step 7: r = q / p, but r ∈ ℤ, so q / p ∈ ℤ
  have q_div_p_int : (q / p : ) = r.num := by
    rw [ r_eq_int]

  -- Step 8: Contradiction
  have : p.natAbs = 1 := by
    have r_den_eq_p : r.den = p.natAbs := by
      by_cases h_pos : 0 < p
      · have p_eq_natAbs : p = p.natAbs := by
          rw [Int.natCast_natAbs, abs_of_pos h_pos]
        have h_den_nat : r.den = p.natAbs := by
          unfold r
          have h_coprime : q.natAbs.Coprime p.natAbs := by
            exact Int.isCoprime_iff_nat_coprime.mp hcoprime
          have h_temp := Rat.den_div_eq_of_coprime h_pos h_coprime
          sorry
        exact h_den_nat
      · have h_nonzero : p  0 := by
          sorry
        have h_neg : p < 0 := lt_of_le_of_ne (not_lt.mp h_pos) h_nonzero
        have eq : q / p = (-q) / p.natAbs := by
          sorry
        sorry
    have p_natAbs_eq_1 : p.natAbs = 1 := by
      rw [ r_den_eq_p,  den_dvd_1]
    exact p_natAbs_eq_1


  -- Contradiction obtained, finish proof
  contradiction

Ruben Van de Velde (Aug 13 2025 at 18:38):

Can you prove that p = (q/p).den? Then it's (r.num : Rat).den and there should be a theorem that that's 1

Nick_adfor (Aug 13 2025 at 18:41):

What's that theorem?

Ruben Van de Velde (Aug 13 2025 at 19:49):

Apparently both docs#Rat.intCast_den and docs#Rat.den_intCast

Nick_adfor (Aug 13 2025 at 20:01):

Ruben Van de Velde said:

Apparently both docs#Rat.intCast_den and docs#Rat.den_intCast

I cannot fix the sorry because of too much more from N to Z. I have no way to do with the last sorry.

Ruben Van de Velde (Aug 13 2025 at 22:44):

Does this help?

import Mathlib

open Matrix Polynomial
/-
Rational eigenvector problem for integer matrices

We prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.
The main tools are the characteristic polynomial and the rational root theorem.
-/

/-- Map an integer matrix A to a rational matrix -/
def Aq {n : } (A : Matrix (Fin n) (Fin n) ) : Matrix (Fin n) (Fin n)  :=
  A.map (Int.castRingHom ) -- Use the ring homomorphism to map each element from ℤ to ℚ

/--
Key lemma: eigenvalue condition translated into a polynomial root
-/
lemma matrix_root_iff_charpoly_root
  {n : } (A : Matrix (Fin n) (Fin n) ) (r : )
  (X : Fin n  ) (hX : X  0) :
  (Aq A).mulVec X = r  X  aeval r (charpoly (Aq A)) = 0 := by
  intro h
  -- Step 1: Show (r•I - A)X = 0
  have hker : (r  (1 : Matrix _ _ ) - Aq A).mulVec X = 0 := by
    rw [Matrix.sub_mulVec, Matrix.smul_mulVec_assoc, one_mulVec, h, sub_self]
  -- Step 2: Non-zero solution implies determinant is 0
  have hdet : (r  (1 : Matrix _ _ ) - Aq A).det = 0 := by
    refine (Matrix.exists_mulVec_eq_zero_iff_aux).mp X, hX, hker
  -- Step 3: Show det(r•I - A) = charpoly(A)(r)
  have : (charpoly (Aq A)).eval r = (r  (1 : Matrix (Fin n) (Fin n) ) - Aq A).det := by
    rw [charpoly, charmatrix, eval_det, scalar_apply, RingHom.mapMatrix_apply, map_sub]
    simp only [scalar_apply, matPolyEquiv_diagonal_X, matPolyEquiv_map_C, eval_sub, eval_X, eval_C, smul_one_eq_diagonal]
  -- Final conclusion
  rw [ this] at hdet
  exact hdet

/-!
Main theorem: only trivial solution exists
-/
theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by
  -- Proof by contradiction: assume there exists a non-zero solution X ≠ 0
  intro X h
  by_contra hX
  push_neg at hX

  -- Define key objects
  let Aℚ := Aq A                    -- Rational matrix
  let r :  := q / p                -- Eigenvalue q/p
  let f : Polynomial  := charpoly Aℚ -- Characteristic polynomial

  -- Step 1: Show r is a root of f
  have h_root : aeval r f = 0 :=
    matrix_root_iff_charpoly_root A r X hX h

  -- Step 2: Relate integer coefficients to rational characteristic polynomial
  have charpoly_map : f = Polynomial.map (Int.castRingHom ) (charpoly A) := by
    simp only [ charpoly_map, Int.coe_castRingHom]
    exact rfl

  -- Step 3: Show leading coefficient is 1
  have leading_one : f.leadingCoeff = 1 := by
    rw [MonCat.one_of,  Monic.def]
    exact charpoly_monic Aℚ

  -- Step 4: Extract numerator and denominator
  let d := r.den  -- Denominator (since r = q/p is reduced, d = p.natAbs)

  -- Step 5: Apply the rational root theorem
  have den_dvd_1 : d = 1 := by
    have A_leading_one : A.charpoly.leadingCoeff = 1 := by
      have := charpoly_monic A
      exact this
    have leading_one' : f.leadingCoeff = 1 := leading_one
    rw [charpoly_map] at leading_one
    have leading_coeff_map : f.leadingCoeff = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [charpoly_map, leading_one]
      exact Rat.ext (id (Eq.symm A_leading_one)) rfl
    have leading_coeff_map' : 1 = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [ leading_coeff_map,  leading_one, charpoly_map]
    have h_root_int : aeval r (charpoly A) = 0 := by
      sorry
    have dvd1 : ((IsFractionRing.den  r) : )  (charpoly A).leadingCoeff := by
      exact den_dvd_of_is_root h_root_int
    rw [A_leading_one] at dvd1
    have abs1 : ((IsFractionRing.den  r : )).natAbs = 1 := by
      have hu : IsUnit (IsFractionRing.den  r : ) :=
        isUnit_of_dvd_one dvd1
      exact Int.natAbs_of_isUnit hu
    sorry
  have r_int : r.den = 1 := den_dvd_1
  have r_eq_int : r = r.num := by
    rw [Rat.coe_int_num_of_den_eq_one den_dvd_1]
  -- Step 7: r = q / p, but r ∈ ℤ, so q / p ∈ ℤ
  have q_div_p_int : (q / p : ) = r.num := by
    rw [ r_eq_int]

  -- Step 8: Contradiction
  have h_coprime : q.natAbs.Coprime p.natAbs := by
    exact Int.isCoprime_iff_nat_coprime.mp hcoprime
  have r_den_eq_p : r.den = p.natAbs := by
    by_cases h_pos : 0 < p
    · have p_eq_natAbs : p = p.natAbs := by
        rw [Int.natCast_natAbs, abs_of_pos h_pos]
      unfold r
      have h_temp := Rat.den_div_eq_of_coprime h_pos h_coprime
      have := h_temp.trans p_eq_natAbs
      simp only [Nat.cast_inj] at this
      exact this
    · have h_nonzero : p  0 := by
        rintro rfl
        simp [r, d, isCoprime_zero_right, Int.isUnit_iff_natAbs_eq] at *
        -- Not sure this is true
        sorry
      have h_neg : p < 0 := lt_of_le_of_ne (not_lt.mp h_pos) h_nonzero
      have h_pos : 0 < -p := by linarith
      have h_temp := Rat.den_div_eq_of_coprime h_pos (by simpa using h_coprime)
      unfold r
      simp only [Int.cast_neg, div_neg, Rat.neg_den] at h_temp
      apply Nat.cast_injective (R := )
      rw [h_temp, Int.ofNat_natAbs_of_nonpos h_neg.le]
  have : p.natAbs = 1 := by
    rw [ r_den_eq_p,  den_dvd_1]


  -- Contradiction obtained, finish proof
  contradiction

Nick_adfor (Aug 14 2025 at 03:29):

That's very kind of you. As p is not 0 can be write in

theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (h_nonzero : p  0) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by

All is fine.

Nick_adfor (Aug 14 2025 at 03:30):

Now with sorry in step 5. I'm quite confused from Z to Q.

import Mathlib

open Matrix Polynomial
/-
Rational eigenvector problem for integer matrices

We prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.
The main tools are the characteristic polynomial and the rational root theorem.
-/

/-- Map an integer matrix A to a rational matrix -/
def Aq {n : } (A : Matrix (Fin n) (Fin n) ) : Matrix (Fin n) (Fin n)  :=
  A.map (Int.castRingHom ) -- Use the ring homomorphism to map each element from ℤ to ℚ

/--
Key lemma: eigenvalue condition translated into a polynomial root
-/
lemma matrix_root_iff_charpoly_root
  {n : } (A : Matrix (Fin n) (Fin n) ) (r : )
  (X : Fin n  ) (hX : X  0) :
  (Aq A).mulVec X = r  X  aeval r (charpoly (Aq A)) = 0 := by
  intro h
  -- Step 1: Show (r•I - A)X = 0
  have hker : (r  (1 : Matrix _ _ ) - Aq A).mulVec X = 0 := by
    rw [Matrix.sub_mulVec, Matrix.smul_mulVec_assoc, one_mulVec, h, sub_self]
  -- Step 2: Non-zero solution implies determinant is 0
  have hdet : (r  (1 : Matrix _ _ ) - Aq A).det = 0 := by
    refine (Matrix.exists_mulVec_eq_zero_iff_aux).mp X, hX, hker
  -- Step 3: Show det(r•I - A) = charpoly(A)(r)
  have : (charpoly (Aq A)).eval r = (r  (1 : Matrix (Fin n) (Fin n) ) - Aq A).det := by
    rw [charpoly, charmatrix, eval_det, scalar_apply, RingHom.mapMatrix_apply, map_sub]
    simp only [scalar_apply, matPolyEquiv_diagonal_X, matPolyEquiv_map_C, eval_sub, eval_X, eval_C, smul_one_eq_diagonal]
  -- Final conclusion
  rw [ this] at hdet
  exact hdet

/--
Main theorem: only trivial solution exists
-/
theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (h_nonzero : p  0) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by
  -- Proof by contradiction: assume there exists a non-zero solution X ≠ 0
  intro X h
  by_contra hX
  push_neg at hX

  -- Define key objects
  let Aℚ := Aq A                    -- Rational matrix
  let r :  := q / p                -- Eigenvalue q/p
  let f : Polynomial  := charpoly Aℚ -- Characteristic polynomial

  -- Step 1: Show r is a root of f
  have h_root : aeval r f = 0 :=
    matrix_root_iff_charpoly_root A r X hX h

  -- Step 2: Relate integer coefficients to rational characteristic polynomial
  have charpoly_map : f = Polynomial.map (Int.castRingHom ) (charpoly A) := by
    simp only [ charpoly_map, Int.coe_castRingHom]
    exact rfl

  -- Step 3: Show leading coefficient is 1
  have leading_one : f.leadingCoeff = 1 := by
    rw [MonCat.one_of,  Monic.def]
    exact charpoly_monic Aℚ

  -- Step 4: Extract numerator and denominator
  let d := r.den

  -- Step 5: Apply the rational root theorem
  have den_dvd_1 : d = 1 := by
    have A_leading_one : A.charpoly.leadingCoeff = 1 := by
      have := charpoly_monic A
      exact this
    have leading_one' : f.leadingCoeff = 1 := leading_one
    rw [charpoly_map] at leading_one
    have leading_coeff_map : f.leadingCoeff = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [charpoly_map, leading_one]
      exact Rat.ext (id (Eq.symm A_leading_one)) rfl
    have leading_coeff_map' : 1 = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [ leading_coeff_map,  leading_one, charpoly_map]
    have h_root_int : aeval r (charpoly A) = 0 := by
      rw [aeval_def] at h_root 
      have : eval₂ (algebraMap  ) r (A.charpoly) = eval₂ (algebraMap  ) r f := by
        rw [charpoly_map, Polynomial.eval₂_map]
        have : (algebraMap  ).comp (Int.castRingHom ) = algebraMap   := by
          ext x
          simp [algebraMap_int_eq]
        rw [this]
      rw [this, h_root]
    have dvd1 : ((IsFractionRing.den  r) : )  (charpoly A).leadingCoeff := by
      exact den_dvd_of_is_root h_root_int
    rw [A_leading_one] at dvd1
    have abs1 : ((IsFractionRing.den  r : )).natAbs = 1 := by
      have hu : IsUnit (IsFractionRing.den  r : ) :=
        isUnit_of_dvd_one dvd1
      exact Int.natAbs_of_isUnit hu
    have den_eq : d = ((IsFractionRing.den  r : )).natAbs := by
      rw [ Rat.num_div_den r]
      have :  (q' : ) (p' : ),
        IsFractionRing.den  r = p' 
        r = algebraMap   q' / algebraMap   p' := by
        sorry
      obtain q', p', h_den, h_frac := this
      have cross_mul : q * p' = p * q' := by
        have h1 : r = q / p := by rw [div_eq_div_iff_comm]
        have h2 : r = q' / p' := by sorry
        have h_eq' : q / p = q' / p' := by sorry
        apply_fun (fun x => x * (p * p')) at h_eq'
        have h_eq : q / p * (p * p') = q' / p' * (p * p') := by
          rw [h_eq']
        have : q / p * (p * p') = q * p' := by sorry
        sorry
      simp [mul_assoc, mul_comm, algebraMap_int_eq] at cross_mul
      have p'_div_p : p'  p := by
        sorry
      have h_coprime : q.natAbs.Coprime p.natAbs := by
        exact Int.isCoprime_iff_nat_coprime.mp hcoprime
      sorry
    rw [ abs1, den_eq]
  have r_int : r.den = 1 := den_dvd_1
  --step 6: r is an integer
  have r_eq_int : r = r.num := by
    rw [Rat.coe_int_num_of_den_eq_one den_dvd_1]
  -- Step 7: r = q / p, but r ∈ ℤ, so q / p ∈ ℤ
  have q_div_p_int : (q / p : ) = r.num := by
    rw [ r_eq_int]

  -- Step 8: Contradiction
  have h_coprime : q.natAbs.Coprime p.natAbs := by
    exact Int.isCoprime_iff_nat_coprime.mp hcoprime
  have : p.natAbs = 1 := by
    have r_den_eq_p : r.den = p.natAbs := by
      by_cases h_pos : 0 < p
      · have p_eq_natAbs : p = p.natAbs := by
          rw [Int.natCast_natAbs, abs_of_pos h_pos]
        unfold r
        have h_temp := Rat.den_div_eq_of_coprime h_pos h_coprime
        have := h_temp.trans p_eq_natAbs
        simp only [Nat.cast_inj] at this
        exact this
      · have h_neg : p < 0 := lt_of_le_of_ne (not_lt.mp h_pos) h_nonzero
        have h_pos : 0 < -p := by linarith
        have h_temp := Rat.den_div_eq_of_coprime h_pos (by simpa using h_coprime)
        unfold r
        simp only [Int.cast_neg, div_neg, Rat.neg_den] at h_temp
        apply Nat.cast_injective (R := )
        rw [h_temp, Int.ofNat_natAbs_of_nonpos h_neg.le]
    have p_natAbs_eq_1 : p.natAbs = 1 := by
      rw [ r_den_eq_p,  den_dvd_1]
    exact p_natAbs_eq_1


  -- Contradiction obtained, finish proof
  contradiction

Ruben Van de Velde (Aug 14 2025 at 07:37):

Ugh, that was more annoying than expected:

import Mathlib

open Matrix Polynomial
/-
Rational eigenvector problem for integer matrices

We prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.
The main tools are the characteristic polynomial and the rational root theorem.
-/

/-- Map an integer matrix A to a rational matrix -/
def Aq {n : } (A : Matrix (Fin n) (Fin n) ) : Matrix (Fin n) (Fin n)  :=
  A.map (Int.castRingHom ) -- Use the ring homomorphism to map each element from ℤ to ℚ

/--
Key lemma: eigenvalue condition translated into a polynomial root
-/
lemma matrix_root_iff_charpoly_root
  {n : } (A : Matrix (Fin n) (Fin n) ) (r : )
  (X : Fin n  ) (hX : X  0) :
  (Aq A).mulVec X = r  X  aeval r (charpoly (Aq A)) = 0 := by
  intro h
  -- Step 1: Show (r•I - A)X = 0
  have hker : (r  (1 : Matrix _ _ ) - Aq A).mulVec X = 0 := by
    rw [Matrix.sub_mulVec, Matrix.smul_mulVec_assoc, one_mulVec, h, sub_self]
  -- Step 2: Non-zero solution implies determinant is 0
  have hdet : (r  (1 : Matrix _ _ ) - Aq A).det = 0 := by
    refine (Matrix.exists_mulVec_eq_zero_iff_aux).mp X, hX, hker
  -- Step 3: Show det(r•I - A) = charpoly(A)(r)
  have : (charpoly (Aq A)).eval r = (r  (1 : Matrix (Fin n) (Fin n) ) - Aq A).det := by
    rw [charpoly, charmatrix, eval_det, scalar_apply, RingHom.mapMatrix_apply, map_sub]
    simp only [scalar_apply, matPolyEquiv_diagonal_X, matPolyEquiv_map_C, eval_sub, eval_X, eval_C, smul_one_eq_diagonal]
  -- Final conclusion
  rw [ this] at hdet
  exact hdet

/-!
Main theorem: only trivial solution exists
-/
theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (h_nonzero : p  0) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by
  -- Proof by contradiction: assume there exists a non-zero solution X ≠ 0
  intro X h
  by_contra hX
  push_neg at hX

  -- Define key objects
  let Aℚ := Aq A                    -- Rational matrix
  let r :  := q / p                -- Eigenvalue q/p
  let f : Polynomial  := charpoly Aℚ -- Characteristic polynomial

  -- Step 1: Show r is a root of f
  have h_root : aeval r f = 0 :=
    matrix_root_iff_charpoly_root A r X hX h

  -- Step 2: Relate integer coefficients to rational characteristic polynomial
  have charpoly_map : f = Polynomial.map (Int.castRingHom ) (charpoly A) := by
    simp only [ charpoly_map, Int.coe_castRingHom]
    exact rfl

  -- Step 3: Show leading coefficient is 1
  have leading_one : f.leadingCoeff = 1 := by
    rw [MonCat.one_of,  Monic.def]
    exact charpoly_monic Aℚ

  -- Step 4: Extract numerator and denominator
  let d := r.den  -- Denominator (since r = q/p is reduced, d = p.natAbs)

  -- Step 5: Apply the rational root theorem
  have den_dvd_1 : d = 1 := by
    have A_leading_one : A.charpoly.leadingCoeff = 1 := by
      have := charpoly_monic A
      exact this
    have leading_one' : f.leadingCoeff = 1 := leading_one
    rw [charpoly_map] at leading_one
    have leading_coeff_map : f.leadingCoeff = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [charpoly_map, leading_one]
      exact Rat.ext (id (Eq.symm A_leading_one)) rfl
    have leading_coeff_map' : 1 = Int.castRingHom  A.charpoly.leadingCoeff := by
      rw [ leading_coeff_map,  leading_one, charpoly_map]
    have h_root_int : aeval r (charpoly A) = 0 := by
      rw [aeval_def] at h_root 
      have : eval₂ (algebraMap  ) r (A.charpoly) = eval₂ (algebraMap  ) r f := by
        rw [charpoly_map, Polynomial.eval₂_map]
        have : (algebraMap  ).comp (Int.castRingHom ) = algebraMap   := by
          ext x
          simp [algebraMap_int_eq]
        rw [this]
      rw [this, h_root]
    have dvd1 : ((IsFractionRing.den  r) : )  (charpoly A).leadingCoeff := by
      exact den_dvd_of_is_root h_root_int
    rw [A_leading_one] at dvd1
    have hu : IsUnit (IsFractionRing.den  r : ) :=
      isUnit_of_dvd_one dvd1
    have abs1 : ((IsFractionRing.den  r : )).natAbs = 1 := by
      exact Int.natAbs_of_isUnit hu
    rw [IsFractionRing.isUnit_den_iff, IsLocalization.IsInteger] at hu
    simp at hu
    obtain r', hr := hu
    unfold d
    rw [ hr]
    simp
  have r_int : r.den = 1 := den_dvd_1
  --step 6: r is an integer
  have r_eq_int : r = r.num := by
    rw [Rat.coe_int_num_of_den_eq_one den_dvd_1]
  -- Step 7: r = q / p, but r ∈ ℤ, so q / p ∈ ℤ
  have q_div_p_int : (q / p : ) = r.num := by
    rw [ r_eq_int]

  -- Step 8: Contradiction
  have h_coprime : q.natAbs.Coprime p.natAbs := by
    exact Int.isCoprime_iff_nat_coprime.mp hcoprime
  have : p.natAbs = 1 := by
    have r_den_eq_p : r.den = p.natAbs := by
      by_cases h_pos : 0 < p
      · have p_eq_natAbs : p = p.natAbs := by
          rw [Int.natCast_natAbs, abs_of_pos h_pos]
        unfold r
        have h_temp := Rat.den_div_eq_of_coprime h_pos h_coprime
        have := h_temp.trans p_eq_natAbs
        simp only [Nat.cast_inj] at this
        exact this
      · have h_neg : p < 0 := lt_of_le_of_ne (not_lt.mp h_pos) h_nonzero
        have h_pos : 0 < -p := by linarith
        have h_temp := Rat.den_div_eq_of_coprime h_pos (by simpa using h_coprime)
        unfold r
        simp only [Int.cast_neg, div_neg, Rat.neg_den] at h_temp
        apply Nat.cast_injective (R := )
        rw [h_temp, Int.ofNat_natAbs_of_nonpos h_neg.le]
    have p_natAbs_eq_1 : p.natAbs = 1 := by
      rw [ r_den_eq_p,  den_dvd_1]
    exact p_natAbs_eq_1


  -- Contradiction obtained, finish proof
  contradiction

Nick_adfor (Aug 14 2025 at 07:40):

It is unbelivable that you fix it in a short time!

Nick_adfor (Aug 14 2025 at 07:42):

IsFractionRing.isUnit_den_iff and IsLocalization.IsInteger are something I have never thought of.

Nick_adfor (Aug 14 2025 at 07:42):

(deleted)

Ruben Van de Velde (Aug 14 2025 at 07:44):

You had the result about IsFractionRing.den, which I didn't really know anything about, so I searched loogle, which only had 14 results, only one of which seemed relevant

Ruben Van de Velde (Aug 14 2025 at 07:46):

In the sense that IsLocalization.IsInteger sounded exactly like what you needed - but not quite in the right form. So I searched for IsLocalization.IsInteger on loogle and didn't really find anything relevant to the concrete Int/Rat case, so I tried simplifying the definition and was lucky that that basically solved it

Ruben Van de Velde (Aug 14 2025 at 07:48):

This was the lemma I was looking for but we don't have yet:

lemma Rat.isLocalizationIsInteger_iff (q : ) :
    IsLocalization.IsInteger  q  q  Set.range Int.cast := by
  simp [IsLocalization.IsInteger]

Nick_adfor (Aug 14 2025 at 07:59):

I cut some unused have and write more notes in. I think the way to find the two needed theorem IsFractionRing.isUnit_den_iff and IsLocalization.IsInteger is totally amazing.

Nick_adfor (Aug 14 2025 at 07:59):

import Mathlib

open Matrix Polynomial

/-
Rational eigenvector problem for integer matrices

We prove: For an integer matrix A, if q/p (p ≠ 1 and q, p coprime) is a rational eigenvalue of A, then the corresponding eigenvector X must be zero.
The main tools are the characteristic polynomial and the rational root theorem.
-/

/-- Map an integer matrix A to a rational matrix -/
def Aq {n : } (A : Matrix (Fin n) (Fin n) ) : Matrix (Fin n) (Fin n)  :=
  A.map (Int.castRingHom )

/--
Key lemma: eigenvalue condition translated into a polynomial root
-/
lemma matrix_root_iff_charpoly_root
  {n : } (A : Matrix (Fin n) (Fin n) ) (r : )
  (X : Fin n  ) (hX : X  0) :
  (Aq A).mulVec X = r  X  aeval r (charpoly (Aq A)) = 0 := by
  intro h
  -- (r•I - A)X = 0
  have hker : (r  (1 : Matrix _ _ ) - Aq A).mulVec X = 0 := by
    rw [Matrix.sub_mulVec, Matrix.smul_mulVec_assoc, one_mulVec, h, sub_self]
  -- Non-zero solution implies determinant is 0
  have hdet : (r  (1 : Matrix _ _ ) - Aq A).det = 0 := by
    refine (Matrix.exists_mulVec_eq_zero_iff_aux).mp X, hX, hker
  -- det(r•I - A) = charpoly(A)(r)
  have : (charpoly (Aq A)).eval r = (r  (1 : Matrix (Fin n) (Fin n) ) - Aq A).det := by
    rw [charpoly, charmatrix, eval_det, scalar_apply, RingHom.mapMatrix_apply, map_sub]
    simp only [scalar_apply, matPolyEquiv_diagonal_X, matPolyEquiv_map_C, eval_sub, eval_X, eval_C, smul_one_eq_diagonal]
  rw [ this] at hdet
  exact hdet

/--
Main theorem: only trivial solution exists
-/
theorem only_trivial_solution
  {n : } (A : Matrix (Fin n) (Fin n) ) (q p : )
  (hp : p.natAbs  1) (h_nonzero : p  0) (hcoprime : IsCoprime q p) :
   (X : Fin n  ), (Aq A).mulVec X = (q / p : )  X  X = 0 := by
  intro X h
  by_contra hX
  push_neg at hX

  let Aℚ := Aq A
  let r :  := q / p
  let f : Polynomial  := charpoly Aℚ

  -- r is a root of the characteristic polynomial
  have h_root : aeval r f = 0 :=
    matrix_root_iff_charpoly_root A r X hX h

  -- Characteristic polynomial relation between ℤ and ℚ
  have charpoly_map : f = Polynomial.map (Int.castRingHom ) (charpoly A) := by
    simp only [ charpoly_map, Int.coe_castRingHom]
    exact rfl

  let d := r.den

-- Denominator must be 1 (rational root theorem)
  have den_dvd_1 : d = 1 := by
    -- The characteristic polynomial of an integer matrix is monic (leading coefficient 1)
    have A_leading_one : A.charpoly.leadingCoeff = 1 := by
      have := charpoly_monic A  -- From Mathlib: charpoly of any matrix over a commutative ring is monic
      exact this

    -- Show r is a root of the integer version of the characteristic polynomial
    have h_root_int : aeval r (charpoly A) = 0 := by
      rw [aeval_def] at h_root 
      -- Relate evaluation of mapped polynomial to original polynomial
      have : eval₂ (algebraMap  ) r (A.charpoly) = eval₂ (algebraMap  ) r f := by
        rw [charpoly_map, Polynomial.eval₂_map]
        -- Show the composition of maps equals the direct integer to rational map
        have : (algebraMap  ).comp (Int.castRingHom ) = algebraMap   := by
          ext x
          simp [algebraMap_int_eq]
        rw [this]
      rw [this, h_root]

    -- By rational root theorem, denominator must divide leading coefficient
    have dvd1 : ((IsFractionRing.den  r) : )  (charpoly A).leadingCoeff := by
      exact den_dvd_of_is_root h_root_int

    -- Since leading coefficient is 1, denominator must divide 1
    rw [A_leading_one] at dvd1
    have hu : IsUnit (IsFractionRing.den  r : ) :=
      isUnit_of_dvd_one dvd1

    -- An integer is a unit iff it's ±1, which means denominator is in the range of algebraMap
    rw [IsFractionRing.isUnit_den_iff, IsLocalization.IsInteger] at hu
    simp only [algebraMap_int_eq, RingHom.mem_rangeS, eq_intCast] at hu
    obtain r', hr := hu

    -- Unfold definition of d and show it equals 1
    unfold d
    rw [ hr]
    simp only [Rat.intCast_den]

  -- Convert coprimality from integers to natural numbers
  have h_coprime : q.natAbs.Coprime p.natAbs := by
    exact Int.isCoprime_iff_nat_coprime.mp hcoprime

  -- Show p.natAbs must equal denominator of r (which we've shown equals 1)
  have : p.natAbs = 1 := by
    -- First show denominator of r equals |p|
    have r_den_eq_p : r.den = p.natAbs := by
      by_cases h_pos : 0 < p
      · -- Case when p is positive
        have p_eq_natAbs : p = p.natAbs := by
          rw [Int.natCast_natAbs, abs_of_pos h_pos]
        unfold r
        -- Rat.den_div_eq_of_coprime gives denominator for reduced fraction
        have h_temp := Rat.den_div_eq_of_coprime h_pos h_coprime
        have := h_temp.trans p_eq_natAbs
        simp only [Nat.cast_inj] at this
        exact this
      · -- Case when p is negative
        have h_neg : p < 0 := lt_of_le_of_ne (not_lt.mp h_pos) h_nonzero
        have h_pos : 0 < -p := by linarith
        -- Similar reasoning for negative p
        have h_temp := Rat.den_div_eq_of_coprime h_pos (by simpa using h_coprime)
        unfold r
        simp only [Int.cast_neg, div_neg, Rat.neg_den] at h_temp
        apply Nat.cast_injective (R := )
        rw [h_temp, Int.ofNat_natAbs_of_nonpos h_neg.le]

    -- Combine with previous result that denominator equals 1
    have p_natAbs_eq_1 : p.natAbs = 1 := by
      rw [ r_den_eq_p,  den_dvd_1]
    exact p_natAbs_eq_1

  contradiction

Ruben Van de Velde (Aug 14 2025 at 08:10):

The more you try, the easier it becomes :)

Ruben Van de Velde (Aug 14 2025 at 08:31):

#28399

Nick_adfor (Aug 14 2025 at 09:20):

Ruben Van de Velde said:

The more you try, the easier it becomes :)

As my hu is in abs1, I can never use hu in the later proof : (

And all I've tried is to rw?, but it can never generate obtain. Also, I'm not familiar with IsFractionRing and IsLocalization, so I will even avoid using them.

Nick_adfor (Aug 14 2025 at 09:27):

Int.castRingHom, IsFractionRing.den, algebraMap, Rat.intcast,
Int.isCoprime in the former code are all generated automatically. But I do not try to read the related name space and package, which is important.

Nick_adfor (Aug 14 2025 at 09:29):

As for IsLocalization.IsInteger, I've never heard of that.


Last updated: Dec 20 2025 at 21:32 UTC