Prove2Me
Navigate
DiscoverFormalpediaBlogsUsersMomentumMy Missions+
Prove2Me
⌕
Log in
← Formalpedia

Evaluation of symmetric multivariate polynomials

Definition
LindemannWeierstrass430_SymmetricEval

by lisamegawatts · Sep 19, 2026 · Mathlib c5ea003 (Lean v4.30.0)

lindemann-weierstrass-lean430-backportnumber-theorytranscendence

This module supplies the evaluation identities for symmetric multivariate polynomials needed to pass from elementary symmetric functions to polynomial root sums. It packages evaluation, renaming, and the fundamental theorem of symmetric polynomials in the exact form consumed by Lindemann--Weierstrass.

Definition code
/-
Copyright (c) 2022 Yuyang Zhao. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yuyang Zhao
-/
import Mathlib.RingTheory.MvPolynomial.Symmetric.FundamentalTheorem
import Mathlib.RingTheory.Polynomial.Vieta

/-!
# Evaluating symmetric polynomials

## Main declarations

* `sum_map_aroots_aeval_mem_range_algebraMap`: Given `k` a multiple of `p.leadingCoeff` and
  `e ≥ q.natDegree`, `k ^ e • ∑ i ∈ p.aroots A, q.aeval i` lies in the base ring.
* `MvPolynomial.symmetricSubalgebra.aevalMultiset` evaluates a symmetric polynomial at the elements
  of a multiset.
* `MvPolynomial.symmetricSubalgebra.sumPolynomial` maps `X` to `∑ i, X i`.

These are used in the proof of Lindemann-Weierstrass.
-/


open Finset
open scoped Polynomial

variable {σ τ R S A : Type*}

namespace MvPolynomial.symmetricSubalgebra

section CommSemiring

variable [Fintype σ] [Fintype τ] [CommRing R] [CommSemiring S] [Algebra R S]

variable (σ R) in
/-- `aevalMultiset` evaluates a symmetric polynomial at the elements of `s`. -/
noncomputable
def aevalMultiset (m : Multiset S) : symmetricSubalgebra σ R →ₐ[R] S :=
  (aeval (fun i : Fin (Fintype.card σ) ↦ m.esymm (i + 1))).comp
    (esymmAlgEquiv (σ := σ) R rfl).symm

theorem aevalMultiset_apply (m : Multiset S) (p : symmetricSubalgebra σ R) :
    aevalMultiset σ R m p =
      aeval (fun i : Fin _ ↦ m.esymm (i + 1)) ((esymmAlgEquiv σ R rfl).symm p) := rfl

theorem aevalMultiset_esymm (m : Multiset S) (i : Fin (Fintype.card σ)) :
    aevalMultiset σ R m ⟨esymm σ R (i + 1), esymm_isSymmetric σ R _⟩ = m.esymm (i + 1) := by
  simp [aevalMultiset_apply, esymmAlgEquiv_symm_apply]

theorem aevalMultiset_map (f : σ → S) (p : symmetricSubalgebra σ R) :
    aevalMultiset σ R (Finset.univ.val.map f) p = aeval f (p : MvPolynomial σ R) := by
  rw [aevalMultiset_apply]
  conv_rhs =>
    rw [← AlgEquiv.apply_symm_apply (esymmAlgEquiv σ R rfl) p]
  simp_rw [esymmAlgEquiv_apply, esymmAlgHom_apply, ← aeval_esymm_eq_multiset_esymm σ R,
    ← comp_aeval, AlgHom.coe_comp, Function.comp_apply]

theorem aevalMultiset_map_of_card_eq (f : τ → S) (p : symmetricSubalgebra σ R)
    (h : Fintype.card σ = Fintype.card τ) :
    aevalMultiset σ R (Finset.univ.val.map f) p =
      aeval (f ∘ Fintype.equivOfCardEq h) (p : MvPolynomial σ R) := by
  rw [← aevalMultiset_map (f ∘ Fintype.equivOfCardEq h) p,
    ← Multiset.map_map f (Fintype.equivOfCardEq h)]
  congr
  refine (congr_arg Finset.val (Finset.map_univ_equiv (Fintype.equivOfCardEq h)).symm).trans ?_
  rw [Finset.map_val, Equiv.coe_toEmbedding]

end CommSemiring

section CommRing

variable [Fintype σ] [Fintype τ] [CommRing R] [CommRing S] [Algebra R S]
  [CommRing A] [IsDomain A] [Algebra S A] [Algebra R A] [IsScalarTower R S A]

variable (σ R) in
private noncomputable
def scaleAEvalRoots (q : S[X]) : symmetricSubalgebra σ R →ₐ[R] S :=
  letI f1 := (aeval (fun i : Fin (Fintype.card σ) ↦ q.leadingCoeff ^ (i : ℕ) * (-1) ^ (i + 1 : ℕ) *
    q.coeff (q.natDegree - (i + 1))))
  letI f2 := (esymmAlgEquiv (σ := σ) R rfl).symm
  f1.comp f2

private theorem scaleAEvalRoots_apply {q : S[X]} {p : symmetricSubalgebra σ R} :
    scaleAEvalRoots σ R q p =
      aeval (fun i : Fin _ ↦ q.leadingCoeff ^ (i : ℕ) * (-1) ^ (↑i + 1 : ℕ) *
        q.coeff (q.natDegree - (i + 1))) ((esymmAlgEquiv σ R rfl).symm p) :=
  rfl

private theorem scaleAEvalRoots_esymm {q : S[X]} {i : Fin (Fintype.card σ)} :
    scaleAEvalRoots σ R q ⟨esymm σ R (i + 1), esymm_isSymmetric σ R _⟩ =
      q.leadingCoeff ^ (i : ℕ) * (-1) ^ (i + 1 : ℕ) * q.coeff (q.natDegree - (i + 1)) := by
  simp [scaleAEvalRoots_apply, esymmAlgEquiv_symm_apply]

private theorem scaleAEvalRoots_eq_aevalMultiset {q : S[X]} {p : symmetricSubalgebra σ R}
    (inj : Function.Injective (algebraMap S A)) (h : Fintype.card σ ≤ q.natDegree)
    (hroots : Multiset.card (q.map (algebraMap S A)).roots = q.natDegree) :
    algebraMap S A (scaleAEvalRoots σ R q p) =
      aevalMultiset σ R ((q.map (algebraMap S A)).roots.map (fun x ↦ q.leadingCoeff • x)) p := by
  rw [scaleAEvalRoots_apply]
  trans aeval (fun i : Fin _ ↦ algebraMap S A (q.leadingCoeff ^ (i + 1 : ℕ)) *
    (q.map (algebraMap S A)).roots.esymm (↑i + 1))
      ((esymmAlgEquiv σ R rfl).symm p)
  · simp_rw [← aeval_algebraMap_apply, Function.comp_def, map_mul, ← Polynomial.coeff_map]
    congr
    funext i
    have hroots' :
        Multiset.card (q.map (algebraMap S A)).roots = (q.map (algebraMap S A)).natDegree := by
      rw [hroots, Polynomial.natDegree_map_eq_of_injective inj]
    rw [Polynomial.coeff_eq_esymm_roots_of_card hroots',
      Polynomial.natDegree_map_eq_of_injective inj, Polynomial.leadingCoeff_map_of_injective inj,
      ← mul_assoc, mul_left_comm, ← mul_assoc, ← mul_assoc, mul_assoc _ _ (_ ^ _),
      pow_add q.leadingCoeff, mul_comm _ (_ ^ 1), pow_one, map_mul]
    swap
    · rw [Polynomial.natDegree_map_eq_of_injective inj]
      exact tsub_le_self
    have h : ↑i + 1 ≤ Polynomial.natDegree q := Nat.add_one_le_iff.mpr (i.2.trans_le h)
    congr 1
    · simp_rw [mul_right_eq_self₀, map_pow, map_neg, map_one, tsub_tsub_cancel_of_le h, ← mul_pow,
        neg_one_mul, neg_neg, one_pow, true_or]
    · rw [tsub_tsub_cancel_of_le h]
  · simp_rw [← Algebra.smul_def, Multiset.pow_smul_esymm, ← aevalMultiset_apply]

variable (σ) in
/-- `sumPolynomial σ p` is the map sending `X` to `∑ i, X i`. -/
noncomputable
def sumPolynomial (p : R[X]) : symmetricSubalgebra σ R :=
  ⟨∑ i, Polynomial.aeval (X i) p, fun e ↦ by
    simp_rw [map_sum, rename, ← Polynomial.aeval_algHom_apply, aeval_X, (· ∘ ·)]
    rw [← Equiv.sum_comp e (fun i ↦ Polynomial.aeval (X i) p)]⟩

theorem coe_sumPolynomial (p : R[X]) :
    (sumPolynomial σ p : MvPolynomial σ R) = ∑ i, Polynomial.aeval (X i) p := rfl

theorem aevalMultiset_sumPolynomial
    {m : Multiset S} {p : R[X]} (hm : Multiset.card m = Fintype.card σ) :
    aevalMultiset σ R m (sumPolynomial σ p) = (m.map (fun x ↦ Polynomial.aeval x p)).sum := by
  have eq_univ_map : m = Finset.univ.val.map (fun i : Fin m.toList.length ↦ m.toList.get i) := by
    have toFinset_finRange : ∀ n, (List.finRange n).toFinset = Finset.univ :=
      fun n ↦ Finset.eq_univ_iff_forall.mpr fun x ↦ List.mem_toFinset.mpr <| List.mem_finRange x
    have : (Finset.univ.val : Multiset (Fin m.toList.length)) = List.finRange m.toList.length := by
      rw [← toFinset_finRange, List.toFinset_val, List.dedup_eq_self.mpr]
      exact List.nodup_finRange _
    rw [this, Multiset.map_coe]
    conv_lhs => rw [← m.coe_toList]
    refine congr_arg _ (List.ext_get ?_ (fun n h₁ h₂ ↦ ?_))
    · rw [List.length_map, List.length_finRange]
    simp only [List.get_eq_getElem, List.getElem_map, List.getElem_finRange, Fin.cast_mk]
  conv_lhs => rw [eq_univ_map]
  rw [aevalMultiset_map_of_card_eq]
  swap
  · rw [Fintype.card_fin, Multiset.length_toList, hm]
  rw [coe_sumPolynomial, map_sum]
  simp_rw [← Polynomial.aeval_algHom_apply, aeval_X, (· ∘ ·)]
  generalize_proofs h
  trans ∑ x : Fin m.toList.length, (Polynomial.aeval (m.toList.get x)) p
  · rw [← Equiv.sum_comp (Fintype.equivOfCardEq h)]
  · rw [Finset.sum_eq_multiset_sum]
    conv_rhs => rw [eq_univ_map, Multiset.map_map, Function.comp_def]

end CommRing

end MvPolynomial.symmetricSubalgebra

namespace Polynomial

/-- Given `k` a multiple of `p.leadingCoeff` and `e ≥ q.natDegree`,
`k ^ e • ∑ i ∈ p.aroots A, q.aeval i` lies in the base ring. -/
theorem sum_map_aroots_aeval_mem_range_algebraMap {R A : Type*}
    [CommRing R] [CommRing A] [IsDomain A] [Algebra R A]
    (p : R[X]) (k : R) (e : ℕ) (q : R[X]) (hk : p.leadingCoeff ∣ k) (he : q.natDegree ≤ e)
    (inj : Function.Injective (algebraMap R A))
    (card_aroots : (p.aroots A).card = p.natDegree) :
    k ^ e • ((p.aroots A).map (q.aeval ·)).sum ∈ Set.range (algebraMap R A) := by
  obtain ⟨k', rfl⟩ := hk; let k := p.leadingCoeff * k'
  have :
    (fun x : A => k ^ e • q.aeval x) =
      (fun x => aeval x (∑ i ∈ range (e + 1), monomial i (k' ^ i * k ^ (e - i) * q.coeff i))) ∘
        fun x => p.leadingCoeff • x := by
    funext x; rw [Function.comp_apply]
    simp_rw [map_sum, aeval_eq_sum_range' (Nat.lt_add_one_iff.mpr he), aeval_monomial, smul_sum]
    refine sum_congr rfl fun i hi => ?_
    rw [← Algebra.smul_def, smul_pow, smul_smul, smul_smul, mul_comm (_ * _) (_ ^ _), ← mul_assoc,
      ← mul_assoc, ← mul_pow, ← pow_add,
      add_tsub_cancel_of_le (Nat.lt_add_one_iff.mp (mem_range.mp hi))]
  rw [Multiset.smul_sum, Multiset.map_map, Function.comp_def, this,
    ← Multiset.map_map _ fun x => p.leadingCoeff • x]
  have h1 : ((p.aroots A).map fun x => p.leadingCoeff • x).card =
      Fintype.card (Fin (p.aroots A).card) := by
    rw [Multiset.card_map, Fintype.card_fin]
  have h2 : Fintype.card (Fin (p.aroots A).card) ≤ p.natDegree := by
    rw [Fintype.card_fin]; exact (card_roots' _).trans natDegree_map_le
  rw [← MvPolynomial.symmetricSubalgebra.aevalMultiset_sumPolynomial h1,
    ← MvPolynomial.symmetricSubalgebra.scaleAEvalRoots_eq_aevalMultiset inj h2 card_aroots]
  exact Set.mem_range_self _

end Polynomial
Source
Yuyang Zhao, mathlib4 PR #28013, Lindemann--Weierstrass theorem, c5ea-compatible snapshot 5abb7c68488b527e4d7ecf5d7bbe085db8d2a388; https://github.com/leanprover-community/mathlib4/pull/28013. Mathematical source: Nathan Jacobson, Basic Algebra I, 2nd ed., §4.12, Theorem 4.22.

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paper
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me