File: Mathlib/Algebra/Module/LinearMap/Polynomial.lean

full_name: Matrix.toMvPolynomial
code: /-- Let `M` be an `(m × n)`-matrix over `R`.
Then `Matrix.toMvPolynomial M` is the family (indexed by `i : m`)
of multivariate polynomials in `n` variables over `R` that evaluates on `c : n → R`
to the dot product of the `i`-th row of `M` with `c`:
`Matrix.toMvPolynomial M i` is the sum of the monomials `C (M i j) * X j`. -/
noncomputable
def toMvPolynomial (M : Matrix m n R) (i : m) : MvPolynomial n R 
goal: MvPolynomial n R

full_name: Matrix.toMvPolynomial_eval_eq_apply
code: lemma toMvPolynomial_eval_eq_apply (M : Matrix m n R) (i : m) (c : n → R) :
    eval c (M.toMvPolynomial i) = (M *ᵥ c) i 
goal: (MvPolynomial.eval c) (M.toMvPolynomial i) = (M *ᵥ c) i

full_name: Matrix.toMvPolynomial_map
code: lemma toMvPolynomial_map (f : R →+* S) (M : Matrix m n R) (i : m) :
    (M.map f).toMvPolynomial i = MvPolynomial.map f (M.toMvPolynomial i) 
goal: (M.map ⇑f).toMvPolynomial i = (MvPolynomial.map f) (M.toMvPolynomial i)

full_name: Matrix.toMvPolynomial_isHomogeneous
code: lemma toMvPolynomial_isHomogeneous (M : Matrix m n R) (i : m) :
    (M.toMvPolynomial i).IsHomogeneous 1 
goal: (M.toMvPolynomial i).IsHomogeneous 1

full_name: Matrix.toMvPolynomial_totalDegree_le
code: lemma toMvPolynomial_totalDegree_le (M : Matrix m n R) (i : m) :
    (M.toMvPolynomial i).totalDegree ≤ 1 
goal: (M.toMvPolynomial i).totalDegree ≤ 1

full_name: Matrix.toMvPolynomial_constantCoeff
code: @[simp]
lemma toMvPolynomial_constantCoeff (M : Matrix m n R) (i : m) :
    constantCoeff (M.toMvPolynomial i) = 0 
goal: MvPolynomial.constantCoeff (M.toMvPolynomial i) = 0

full_name: Matrix.toMvPolynomial_zero
code: @[simp]
lemma toMvPolynomial_zero : (0 : Matrix m n R).toMvPolynomial = 0 
goal: Matrix.toMvPolynomial 0 = 0

full_name: Matrix.toMvPolynomial_one
code: @[simp]
lemma toMvPolynomial_one [DecidableEq n] : (1 : Matrix n n R).toMvPolynomial = X 
goal: Matrix.toMvPolynomial 1 = MvPolynomial.X

full_name: Matrix.toMvPolynomial_add
code: lemma toMvPolynomial_add (M N : Matrix m n R) :
    (M + N).toMvPolynomial = M.toMvPolynomial + N.toMvPolynomial 
goal: (M + N).toMvPolynomial = M.toMvPolynomial + N.toMvPolynomial

full_name: Matrix.toMvPolynomial_mul
code: lemma toMvPolynomial_mul (M : Matrix m n R) (N : Matrix n o R) (i : m) :
    (M * N).toMvPolynomial i = bind₁ N.toMvPolynomial (M.toMvPolynomial i) 
goal: (M * N).toMvPolynomial i = (MvPolynomial.bind₁ N.toMvPolynomial) (M.toMvPolynomial i)

full_name: LinearMap.toMvPolynomial
code: /-- Let `f : M₁ →ₗ[R] M₂` be an `R`-linear map
between modules `M₁` and `M₂` with bases `b₁` and `b₂` respectively.
Then `LinearMap.toMvPolynomial b₁ b₂ f` is the family of multivariate polynomials over `R`
that evaluates on an element `x` of `M₁` (represented on the basis `b₁`)
to the element `f x` of `M₂` (represented on the basis `b₂`). -/
noncomputable
def toMvPolynomial (f : M₁ →ₗ[R] M₂) (i : ι₂) :
    MvPolynomial ι₁ R 
goal: MvPolynomial ι₁ R

full_name: LinearMap.toMvPolynomial_eval_eq_apply
code: lemma toMvPolynomial_eval_eq_apply (f : M₁ →ₗ[R] M₂) (i : ι₂) (c : ι₁ →₀ R) :
    eval c (f.toMvPolynomial b₁ b₂ i) = b₂.repr (f (b₁.repr.symm c)) i 
goal: (MvPolynomial.eval ⇑c) (LinearMap.toMvPolynomial b₁ b₂ f i) = (b₂.repr (f (b₁.repr.symm c))) i

full_name: LinearMap.toMvPolynomial_baseChange
code: lemma toMvPolynomial_baseChange (f : M₁ →ₗ[R] M₂) (i : ι₂) (A : Type*) [CommRing A] [Algebra R A] :
    (f.baseChange A).toMvPolynomial (basis A b₁) (basis A b₂) i =
      MvPolynomial.map (algebraMap R A) (f.toMvPolynomial b₁ b₂ i) 
goal: LinearMap.toMvPolynomial (Algebra.TensorProduct.basis A b₁) (Algebra.TensorProduct.basis A b₂)
    (LinearMap.baseChange A f) i =
  (MvPolynomial.map (algebraMap R A)) (LinearMap.toMvPolynomial b₁ b₂ f i)

full_name: LinearMap.toMvPolynomial_isHomogeneous
code: lemma toMvPolynomial_isHomogeneous (f : M₁ →ₗ[R] M₂) (i : ι₂) :
    (f.toMvPolynomial b₁ b₂ i).IsHomogeneous 1 
goal: (LinearMap.toMvPolynomial b₁ b₂ f i).IsHomogeneous 1

full_name: LinearMap.toMvPolynomial_totalDegree_le
code: lemma toMvPolynomial_totalDegree_le (f : M₁ →ₗ[R] M₂) (i : ι₂) :
    (f.toMvPolynomial b₁ b₂ i).totalDegree ≤ 1 
goal: (LinearMap.toMvPolynomial b₁ b₂ f i).totalDegree ≤ 1

full_name: LinearMap.toMvPolynomial_constantCoeff
code: @[simp]
lemma toMvPolynomial_constantCoeff (f : M₁ →ₗ[R] M₂) (i : ι₂) :
    constantCoeff (f.toMvPolynomial b₁ b₂ i) = 0 
goal: MvPolynomial.constantCoeff (LinearMap.toMvPolynomial b₁ b₂ f i) = 0

full_name: LinearMap.toMvPolynomial_zero
code: @[simp]
lemma toMvPolynomial_zero : (0 : M₁ →ₗ[R] M₂).toMvPolynomial b₁ b₂ = 0 
goal: LinearMap.toMvPolynomial b₁ b₂ 0 = 0

full_name: LinearMap.toMvPolynomial_id
code: @[simp]
lemma toMvPolynomial_id : (id : M₁ →ₗ[R] M₁).toMvPolynomial b₁ b₁ = X 
goal: LinearMap.toMvPolynomial b₁ b₁ LinearMap.id = MvPolynomial.X

full_name: LinearMap.toMvPolynomial_add
code: lemma toMvPolynomial_add (f g : M₁ →ₗ[R] M₂) :
    (f + g).toMvPolynomial b₁ b₂ = f.toMvPolynomial b₁ b₂ + g.toMvPolynomial b₁ b₂ 
goal: LinearMap.toMvPolynomial b₁ b₂ (f + g) = LinearMap.toMvPolynomial b₁ b₂ f + LinearMap.toMvPolynomial b₁ b₂ g

full_name: LinearMap.toMvPolynomial_comp
code: lemma toMvPolynomial_comp (g : M₂ →ₗ[R] M₃) (f : M₁ →ₗ[R] M₂) (i : ι₃) :
    (g ∘ₗ f).toMvPolynomial b₁ b₃ i =
      bind₁ (f.toMvPolynomial b₁ b₂) (g.toMvPolynomial b₂ b₃ i) 
goal: LinearMap.toMvPolynomial b₁ b₃ (g ∘ₗ f) i =
  (MvPolynomial.bind₁ (LinearMap.toMvPolynomial b₁ b₂ f)) (LinearMap.toMvPolynomial b₂ b₃ g i)

full_name: LinearMap.polyCharpolyAux
code: /-- (Implementation detail, see `LinearMap.polyCharpoly`.)

Let `L` and `M` be finite free modules over `R`,
and let `φ : L →ₗ[R] Module.End R M` be a linear map.
Let `b` be a basis of `L` and `bₘ` a basis of `M`.
Then `LinearMap.polyCharpolyAux φ b bₘ` is the polynomial that evaluates on elements `x` of `L`
to the characteristic polynomial of `φ x` acting on `M`.

This definition does not depend on the choice of `bₘ`
(see `LinearMap.polyCharpolyAux_basisIndep`). -/
noncomputable
def polyCharpolyAux : Polynomial (MvPolynomial ι R) 
goal: Polynomial (MvPolynomial ι R)

full_name: LinearMap.polyCharpolyAux_baseChange
code: lemma polyCharpolyAux_baseChange (A : Type*) [CommRing A] [Algebra R A] :
    polyCharpolyAux (tensorProduct _ _ _ _ ∘ₗ φ.baseChange A) (basis A b) (basis A bₘ) =
      (polyCharpolyAux φ b bₘ).map (MvPolynomial.map (algebraMap R A)) 
goal: (LinearMap.tensorProduct R A M M ∘ₗ LinearMap.baseChange A φ).polyCharpolyAux (Algebra.TensorProduct.basis A b)
    (Algebra.TensorProduct.basis A bₘ) =
  Polynomial.map (MvPolynomial.map (algebraMap R A)) (φ.polyCharpolyAux b bₘ)

full_name: LinearMap.polyCharpolyAux_map_eq_toMatrix_charpoly
code: lemma polyCharpolyAux_map_eq_toMatrix_charpoly (x : L) :
    (polyCharpolyAux φ b bₘ).map (MvPolynomial.eval (b.repr x)) =
      (toMatrix bₘ bₘ (φ x)).charpoly 
goal: Polynomial.map (MvPolynomial.eval ⇑(b.repr x)) (φ.polyCharpolyAux b bₘ) = ((LinearMap.toMatrix bₘ bₘ) (φ x)).charpoly

full_name: LinearMap.polyCharpolyAux_eval_eq_toMatrix_charpoly_coeff
code: lemma polyCharpolyAux_eval_eq_toMatrix_charpoly_coeff (x : L) (i : ℕ) :
    MvPolynomial.eval (b.repr x) ((polyCharpolyAux φ b bₘ).coeff i) =
      (toMatrix bₘ bₘ (φ x)).charpoly.coeff i 
goal: (MvPolynomial.eval ⇑(b.repr x)) ((φ.polyCharpolyAux b bₘ).coeff i) = ((LinearMap.toMatrix bₘ bₘ) (φ x)).charpoly.coeff i

full_name: LinearMap.polyCharpolyAux_map_eq_charpoly
code: @[simp]
lemma polyCharpolyAux_map_eq_charpoly [Module.Finite R M] [Module.Free R M]
    (x : L) :
    (polyCharpolyAux φ b bₘ).map (MvPolynomial.eval (b.repr x)) = (φ x).charpoly 
goal: Polynomial.map (MvPolynomial.eval ⇑(b.repr x)) (φ.polyCharpolyAux b bₘ) = LinearMap.charpoly (φ x)

full_name: LinearMap.polyCharpolyAux_coeff_eval
code: @[simp]
lemma polyCharpolyAux_coeff_eval [Module.Finite R M] [Module.Free R M] (x : L) (i : ℕ) :
    MvPolynomial.eval (b.repr x) ((polyCharpolyAux φ b bₘ).coeff i) = (φ x).charpoly.coeff i 
goal: (MvPolynomial.eval ⇑(b.repr x)) ((φ.polyCharpolyAux b bₘ).coeff i) = (LinearMap.charpoly (φ x)).coeff i

full_name: LinearMap.polyCharpolyAux_map_eval
code: lemma polyCharpolyAux_map_eval [Module.Finite R M] [Module.Free R M]
    (x : ι → R) :
    (polyCharpolyAux φ b bₘ).map (MvPolynomial.eval x) =
      (φ (b.repr.symm (Finsupp.equivFunOnFinite.symm x))).charpoly 
goal: Polynomial.map (MvPolynomial.eval x) (φ.polyCharpolyAux b bₘ) =
  LinearMap.charpoly (φ (b.repr.symm (Finsupp.equivFunOnFinite.symm x)))

full_name: LinearMap.polyCharpolyAux_map_aeval
code: lemma polyCharpolyAux_map_aeval
    (A : Type*) [CommRing A] [Algebra R A] [Module.Finite A (A ⊗[R] M)] [Module.Free A (A ⊗[R] M)]
    (x : ι → A) :
    (polyCharpolyAux φ b bₘ).map (MvPolynomial.aeval x).toRingHom =
      LinearMap.charpoly ((tensorProduct R A M M).comp (baseChange A φ)
        ((basis A b).repr.symm (Finsupp.equivFunOnFinite.symm x))) 
goal: Polynomial.map (MvPolynomial.aeval x).toRingHom (φ.polyCharpolyAux b bₘ) =
  ((LinearMap.tensorProduct R A M M ∘ₗ LinearMap.baseChange A φ)
      ((Algebra.TensorProduct.basis A b).repr.symm (Finsupp.equivFunOnFinite.symm x))).charpoly

full_name: LinearMap.polyCharpolyAux_basisIndep
code: /-- `LinearMap.polyCharpolyAux` is independent of the choice of basis of the target module.

Proof strategy:
1. Rewrite `polyCharpolyAux` as the (honest, ordinary) characteristic polynomial
   of the basechange of `φ` to the multivariate polynomial ring `MvPolynomial ι R`.
2. Use that the characteristic polynomial of a linear map is independent of the choice of basis.
   This independence result is used transitively via
   `LinearMap.polyCharpolyAux_map_aeval` and `LinearMap.polyCharpolyAux_map_eq_charpoly`. -/
lemma polyCharpolyAux_basisIndep {ιM' : Type*} [Fintype ιM'] [DecidableEq ιM']
    (bₘ' : Basis ιM' R M) :
    polyCharpolyAux φ b bₘ = polyCharpolyAux φ b bₘ' 
goal: φ.polyCharpolyAux b bₘ = φ.polyCharpolyAux b bₘ'

full_name: LinearMap.polyCharpoly
code: /-- Let `L` and `M` be finite free modules over `R`,
and let `φ : L →ₗ[R] Module.End R M` be a linear family of endomorphisms.
Let `b` be a basis of `L` and `bₘ` a basis of `M`.
Then `LinearMap.polyCharpoly φ b` is the polynomial that evaluates on elements `x` of `L`
to the characteristic polynomial of `φ x` acting on `M`. -/
noncomputable
def polyCharpoly : Polynomial (MvPolynomial ι R) 
goal: Polynomial (MvPolynomial ι R)

full_name: LinearMap.polyCharpoly_eq_of_basis
code: lemma polyCharpoly_eq_of_basis [DecidableEq ιM] (bₘ : Basis ιM R M) :
    polyCharpoly φ b =
    (charpoly.univ R ιM).map (MvPolynomial.bind₁ (φ.toMvPolynomial b bₘ.end)) 
goal: φ.polyCharpoly b =
  Polynomial.map (↑(MvPolynomial.bind₁ (LinearMap.toMvPolynomial b bₘ.end φ))) (Matrix.charpoly.univ R ιM)

full_name: LinearMap.polyCharpoly_monic
code: lemma polyCharpoly_monic : (polyCharpoly φ b).Monic 
goal: (φ.polyCharpoly b).Monic

full_name: LinearMap.polyCharpoly_ne_zero
code: lemma polyCharpoly_ne_zero [Nontrivial R] : (polyCharpoly φ b) ≠ 0 
goal: φ.polyCharpoly b ≠ 0

full_name: LinearMap.polyCharpoly_natDegree
code: @[simp]
lemma polyCharpoly_natDegree [Nontrivial R] :
    (polyCharpoly φ b).natDegree = finrank R M 
goal: (φ.polyCharpoly b).natDegree = FiniteDimensional.finrank R M

full_name: LinearMap.polyCharpoly_coeff_isHomogeneous
code: lemma polyCharpoly_coeff_isHomogeneous (i j : ℕ) (hij : i + j = finrank R M) [Nontrivial R] :
    ((polyCharpoly φ b).coeff i).IsHomogeneous j 
goal: ((φ.polyCharpoly b).coeff i).IsHomogeneous j

full_name: LinearMap.polyCharpoly_baseChange
code: lemma polyCharpoly_baseChange (A : Type*) [CommRing A] [Algebra R A] :
    polyCharpoly (tensorProduct _ _ _ _ ∘ₗ φ.baseChange A) (basis A b) =
      (polyCharpoly φ b).map (MvPolynomial.map (algebraMap R A)) 
goal: (LinearMap.tensorProduct R A M M ∘ₗ LinearMap.baseChange A φ).polyCharpoly (Algebra.TensorProduct.basis A b) =
  Polynomial.map (MvPolynomial.map (algebraMap R A)) (φ.polyCharpoly b)

full_name: LinearMap.polyCharpoly_map_eq_charpoly
code: @[simp]
lemma polyCharpoly_map_eq_charpoly (x : L) :
    (polyCharpoly φ b).map (MvPolynomial.eval (b.repr x)) = (φ x).charpoly 
goal: Polynomial.map (MvPolynomial.eval ⇑(b.repr x)) (φ.polyCharpoly b) = LinearMap.charpoly (φ x)

full_name: LinearMap.polyCharpoly_coeff_eval
code: @[simp]
lemma polyCharpoly_coeff_eval (x : L) (i : ℕ) :
    MvPolynomial.eval (b.repr x) ((polyCharpoly φ b).coeff i) = (φ x).charpoly.coeff i 
goal: (MvPolynomial.eval ⇑(b.repr x)) ((φ.polyCharpoly b).coeff i) = (LinearMap.charpoly (φ x)).coeff i

full_name: LinearMap.polyCharpoly_coeff_eq_zero_of_basis
code: lemma polyCharpoly_coeff_eq_zero_of_basis (b : Basis ι R L) (b' : Basis ι' R L) (k : ℕ)
    (H : (polyCharpoly φ b).coeff k = 0) :
    (polyCharpoly φ b').coeff k = 0 
goal: (φ.polyCharpoly b').coeff k = 0

full_name: LinearMap.polyCharpoly_coeff_eq_zero_iff_of_basis
code: lemma polyCharpoly_coeff_eq_zero_iff_of_basis (b : Basis ι R L) (b' : Basis ι' R L) (k : ℕ) :
    (polyCharpoly φ b).coeff k = 0 ↔ (polyCharpoly φ b').coeff k = 0 
goal: (φ.polyCharpoly b).coeff k = 0 ↔ (φ.polyCharpoly b').coeff k = 0

full_name: LinearMap.nilRankAux
code: /-- (Implementation detail, see `LinearMap.nilRank`.)

Let `L` and `M` be finite free modules over `R`,
and let `φ : L →ₗ[R] Module.End R M` be a linear family of endomorphisms.
Then `LinearMap.nilRankAux φ b` is the smallest index
at which `LinearMap.polyCharpoly φ b` has a non-zero coefficient.

This number does not depend on the choice of `b`, see `nilRankAux_basis_indep`. -/
noncomputable
def nilRankAux (φ : L →ₗ[R] Module.End R M) (b : Basis ι R L) : ℕ 
goal: ℕ

full_name: LinearMap.polyCharpoly_coeff_nilRankAux_ne_zero
code: lemma polyCharpoly_coeff_nilRankAux_ne_zero [Nontrivial R] :
    (polyCharpoly φ b).coeff (nilRankAux φ b) ≠ 0 
goal: (φ.polyCharpoly b).coeff (φ.nilRankAux b) ≠ 0

full_name: LinearMap.nilRankAux_le
code: lemma nilRankAux_le [Nontrivial R] (b : Basis ι R L) (b' : Basis ι' R L) :
    nilRankAux φ b ≤ nilRankAux φ b' 
goal: φ.nilRankAux b ≤ φ.nilRankAux b'

full_name: LinearMap.nilRankAux_basis_indep
code: lemma nilRankAux_basis_indep [Nontrivial R] (b : Basis ι R L) (b' : Basis ι' R L) :
    nilRankAux φ b = (polyCharpoly φ b').natTrailingDegree 
goal: φ.nilRankAux b = (φ.polyCharpoly b').natTrailingDegree

full_name: LinearMap.nilRank
code: /-- Let `L` and `M` be finite free modules over `R`,
and let `φ : L →ₗ[R] Module.End R M` be a linear family of endomorphisms.
Then `LinearMap.nilRank φ b` is the smallest index
at which `LinearMap.polyCharpoly φ b` has a non-zero coefficient.

This number does not depend on the choice of `b`,
see `LinearMap.nilRank_eq_polyCharpoly_natTrailingDegree`. -/
noncomputable
def nilRank (φ : L →ₗ[R] Module.End R M) : ℕ 
goal: ℕ

full_name: LinearMap.nilRank_eq_polyCharpoly_natTrailingDegree
code: lemma nilRank_eq_polyCharpoly_natTrailingDegree (b : Basis ι R L) :
    nilRank φ = (polyCharpoly φ b).natTrailingDegree 
goal: φ.nilRank = (φ.polyCharpoly b).natTrailingDegree

full_name: LinearMap.polyCharpoly_coeff_nilRank_ne_zero
code: lemma polyCharpoly_coeff_nilRank_ne_zero :
    (polyCharpoly φ b).coeff (nilRank φ) ≠ 0 
goal: (φ.polyCharpoly b).coeff φ.nilRank ≠ 0

full_name: LinearMap.nilRank_le_card
code: lemma nilRank_le_card (b : Basis ι R M) : nilRank φ ≤ Fintype.card ι 
goal: φ.nilRank ≤ Fintype.card ι

full_name: LinearMap.nilRank_le_finrank
code: lemma nilRank_le_finrank : nilRank φ ≤ finrank R M 
goal: φ.nilRank ≤ FiniteDimensional.finrank R M

full_name: LinearMap.nilRank_le_natTrailingDegree_charpoly
code: lemma nilRank_le_natTrailingDegree_charpoly (x : L) :
    nilRank φ ≤ (φ x).charpoly.natTrailingDegree 
goal: φ.nilRank ≤ (LinearMap.charpoly (φ x)).natTrailingDegree

full_name: LinearMap.IsNilRegular
code: /-- Let `L` and `M` be finite free modules over `R`,
and let `φ : L →ₗ[R] Module.End R M` be a linear family of endomorphisms,
and denote `n := nilRank φ`.

An element `x : L` is *nil-regular* with respect to `φ`
if the `n`-th coefficient of the characteristic polynomial of `φ x` is non-zero. -/
def IsNilRegular (x : L) : Prop 
goal: Prop

full_name: LinearMap.isNilRegular_def
code: lemma isNilRegular_def :
    IsNilRegular φ x ↔ (Polynomial.coeff (φ x).charpoly (nilRank φ) ≠ 0) 
goal: φ.IsNilRegular x ↔ (LinearMap.charpoly (φ x)).coeff φ.nilRank ≠ 0

full_name: LinearMap.isNilRegular_iff_coeff_polyCharpoly_nilRank_ne_zero
code: lemma isNilRegular_iff_coeff_polyCharpoly_nilRank_ne_zero :
    IsNilRegular φ x ↔
    MvPolynomial.eval (b.repr x)
      ((polyCharpoly φ b).coeff (nilRank φ)) ≠ 0 
goal: φ.IsNilRegular x ↔ (MvPolynomial.eval ⇑(b.repr x)) ((φ.polyCharpoly b).coeff φ.nilRank) ≠ 0

full_name: LinearMap.isNilRegular_iff_natTrailingDegree_charpoly_eq_nilRank
code: lemma isNilRegular_iff_natTrailingDegree_charpoly_eq_nilRank :
    IsNilRegular φ x ↔ (φ x).charpoly.natTrailingDegree = nilRank φ 
goal: φ.IsNilRegular x ↔ (LinearMap.charpoly (φ x)).natTrailingDegree = φ.nilRank

full_name: LinearMap.exists_isNilRegular_of_finrank_le_card
code: lemma exists_isNilRegular_of_finrank_le_card (h : finrank R M ≤ #R) :
    ∃ x : L, IsNilRegular φ x 
goal: ∃ x, φ.IsNilRegular x

full_name: LinearMap.exists_isNilRegular
code: lemma exists_isNilRegular [Infinite R] : ∃ x : L, IsNilRegular φ x 
goal: ∃ x, φ.IsNilRegular x