/-
Copyright (c) 2020 Aaron Anderson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Aaron Anderson, Jalex Stark

! This file was ported from Lean 3 source module algebra.polynomial.big_operators
! leanprover-community/mathlib commit 69c6a5a12d8a2b159f20933e60115a4f2de62b58
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Order.WithZero
import Mathbin.Data.Polynomial.Monic

/-!
# Lemmas for the interaction between polynomials and `∑` and `∏`.

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

Recall that `∑` and `∏` are notation for `finset.sum` and `finset.prod` respectively.

## Main results

- `polynomial.nat_degree_prod_of_monic` : the degree of a product of monic polynomials is the
  product of degrees. We prove this only for `[comm_semiring R]`,
  but it ought to be true for `[semiring R]` and `list.prod`.
- `polynomial.nat_degree_prod` : for polynomials over an integral domain,
  the degree of the product is the sum of degrees.
- `polynomial.leading_coeff_prod` : for polynomials over an integral domain,
  the leading coefficient is the product of leading coefficients.
- `polynomial.prod_X_sub_C_coeff_card_pred` carries most of the content for computing
  the second coefficient of the characteristic polynomial.
-/

open Finset

open Multiset

open BigOperators Polynomial

universe u w

variable {R : Type u} {ι : Type w}

namespace Polynomial

variable (s : Finset ι)

section Semiring

variable {S : Type _} [Semiring S]

/- warning: polynomial.nat_degree_list_sum_le -> Polynomial.natDegree_list_sum_le is a dubious translation:
lean 3 declaration is
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u1} S _inst_1 (List.sum.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.add'.{u1} S _inst_1) (Polynomial.zero.{u1} S _inst_1) l)) (List.foldr.{0, 0} Nat Nat (LinearOrder.max.{0} Nat Nat.linearOrder) (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) (List.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
but is expected to have type
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} S _inst_1 (List.sum.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.add'.{u1} S _inst_1) (Polynomial.zero.{u1} S _inst_1) l)) (List.foldr.{0, 0} Nat Nat (Max.max.{0} Nat Nat.instMaxNat) (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) (List.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_list_sum_le Polynomial.natDegree_list_sum_leₓ'. -/
theorem natDegree_list_sum_le (l : List S[X]) : natDegree l.Sum ≤ (l.map natDegree).foldr max 0 :=
  List.sum_le_foldr_max natDegree (by simp) natDegree_add_le _
#align polynomial.nat_degree_list_sum_le Polynomial.natDegree_list_sum_le

/- warning: polynomial.nat_degree_multiset_sum_le -> Polynomial.natDegree_multiset_sum_le is a dubious translation:
lean 3 declaration is
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : Multiset.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u1} S _inst_1 (Multiset.sum.{u1} (Polynomial.{u1} S _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} (Polynomial.{u1} S _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.semiring.{u1} S _inst_1)))) l)) (Multiset.foldr.{0, 0} Nat Nat (LinearOrder.max.{0} Nat Nat.linearOrder) (max_left_comm.{0} Nat Nat.linearOrder) (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) (Multiset.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
but is expected to have type
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : Multiset.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} S _inst_1 (Multiset.sum.{u1} (Polynomial.{u1} S _inst_1) (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} (Polynomial.{u1} S _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.semiring.{u1} S _inst_1)))) l)) (Multiset.foldr.{0, 0} Nat Nat (Max.max.{0} Nat (LinearOrder.toMax.{0} Nat Nat.linearOrder)) (max_left_comm.{0} Nat Nat.linearOrder) (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) (Multiset.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_multiset_sum_le Polynomial.natDegree_multiset_sum_leₓ'. -/
theorem natDegree_multiset_sum_le (l : Multiset S[X]) :
    natDegree l.Sum ≤ (l.map natDegree).foldr max max_left_comm 0 :=
  Quotient.inductionOn l (by simpa using nat_degree_list_sum_le)
#align polynomial.nat_degree_multiset_sum_le Polynomial.natDegree_multiset_sum_le

/- warning: polynomial.nat_degree_sum_le -> Polynomial.natDegree_sum_le is a dubious translation:
lean 3 declaration is
  forall {ι : Type.{u1}} (s : Finset.{u1} ι) {S : Type.{u2}} [_inst_1 : Semiring.{u2} S] (f : ι -> (Polynomial.{u2} S _inst_1)), LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u2} S _inst_1 (Finset.sum.{u2, u1} (Polynomial.{u2} S _inst_1) ι (NonUnitalNonAssocSemiring.toAddCommMonoid.{u2} (Polynomial.{u2} S _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} (Polynomial.{u2} S _inst_1) (Semiring.toNonAssocSemiring.{u2} (Polynomial.{u2} S _inst_1) (Polynomial.semiring.{u2} S _inst_1)))) s (fun (i : ι) => f i))) (Finset.fold.{u1, 0} ι Nat (LinearOrder.max.{0} Nat Nat.linearOrder) (sup_isCommutative.{0} Nat (CanonicallyLinearOrderedAddMonoid.semilatticeSup.{0} Nat Nat.canonicallyLinearOrderedAddMonoid)) (sup_isAssociative.{0} Nat (CanonicallyLinearOrderedAddMonoid.semilatticeSup.{0} Nat Nat.canonicallyLinearOrderedAddMonoid)) (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) (Function.comp.{succ u1, succ u2, 1} ι (Polynomial.{u2} S _inst_1) Nat (Polynomial.natDegree.{u2} S _inst_1) f) s)
but is expected to have type
  forall {ι : Type.{u2}} (s : Finset.{u2} ι) {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (f : ι -> (Polynomial.{u1} S _inst_1)), LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} S _inst_1 (Finset.sum.{u1, u2} (Polynomial.{u1} S _inst_1) ι (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} (Polynomial.{u1} S _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.semiring.{u1} S _inst_1)))) s (fun (i : ι) => f i))) (Finset.fold.{u2, 0} ι Nat (Max.max.{0} Nat (LinearOrder.toMax.{0} Nat Nat.linearOrder)) (instIsCommutativeMaxToMax.{0} Nat Nat.linearOrder) (instIsAssociativeMaxToMax.{0} Nat Nat.linearOrder) (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) (Function.comp.{succ u2, succ u1, 1} ι (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) f) s)
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_sum_le Polynomial.natDegree_sum_leₓ'. -/
theorem natDegree_sum_le (f : ι → S[X]) :
    natDegree (∑ i in s, f i) ≤ s.fold max 0 (natDegree ∘ f) := by
  simpa using nat_degree_multiset_sum_le (s.val.map f)
#align polynomial.nat_degree_sum_le Polynomial.natDegree_sum_le

/- warning: polynomial.degree_list_sum_le -> Polynomial.degree_list_sum_le is a dubious translation:
lean 3 declaration is
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} (WithBot.{0} Nat) (Preorder.toLE.{0} (WithBot.{0} Nat) (WithBot.preorder.{0} Nat (PartialOrder.toPreorder.{0} Nat (OrderedCancelAddCommMonoid.toPartialOrder.{0} Nat (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{0} Nat Nat.strictOrderedSemiring))))) (Polynomial.degree.{u1} S _inst_1 (List.sum.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.add'.{u1} S _inst_1) (Polynomial.zero.{u1} S _inst_1) l)) (List.maximum.{0} Nat (PartialOrder.toPreorder.{0} Nat (OrderedCancelAddCommMonoid.toPartialOrder.{0} Nat (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{0} Nat Nat.strictOrderedSemiring))) (fun (a : Nat) (b : Nat) => Nat.decidableLt a b) (List.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
but is expected to have type
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)), LE.le.{0} (WithBot.{0} Nat) (Preorder.toLE.{0} (WithBot.{0} Nat) (WithBot.preorder.{0} Nat (PartialOrder.toPreorder.{0} Nat (StrictOrderedSemiring.toPartialOrder.{0} Nat Nat.strictOrderedSemiring)))) (Polynomial.degree.{u1} S _inst_1 (List.sum.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.add'.{u1} S _inst_1) (Polynomial.zero.{u1} S _inst_1) l)) (List.maximum.{0} Nat (PartialOrder.toPreorder.{0} Nat (StrictOrderedSemiring.toPartialOrder.{0} Nat Nat.strictOrderedSemiring)) (fun (a : Nat) (b : Nat) => Nat.decLt a b) (List.map.{u1, 0} (Polynomial.{u1} S _inst_1) Nat (Polynomial.natDegree.{u1} S _inst_1) l))
Case conversion may be inaccurate. Consider using '#align polynomial.degree_list_sum_le Polynomial.degree_list_sum_leₓ'. -/
theorem degree_list_sum_le (l : List S[X]) : degree l.Sum ≤ (l.map natDegree).maximum :=
  by
  by_cases h : l.sum = 0
  · simp [h]
  · rw [degree_eq_nat_degree h]
    suffices (l.map nat_degree).maximum = ((l.map nat_degree).foldr max 0 : ℕ)
      by
      rw [this]
      simpa [this] using nat_degree_list_sum_le l
    rw [← List.foldr_max_of_ne_nil]
    · congr
    contrapose! h
    rw [List.map_eq_nil] at h
    simp [h]
#align polynomial.degree_list_sum_le Polynomial.degree_list_sum_le

#print Polynomial.natDegree_list_prod_le /-
theorem natDegree_list_prod_le (l : List S[X]) : natDegree l.Prod ≤ (l.map natDegree).Sum :=
  by
  induction' l with hd tl IH
  · simp
  · simpa using nat_degree_mul_le.trans (add_le_add_left IH _)
#align polynomial.nat_degree_list_prod_le Polynomial.natDegree_list_prod_le
-/

#print Polynomial.degree_list_prod_le /-
theorem degree_list_prod_le (l : List S[X]) : degree l.Prod ≤ (l.map degree).Sum :=
  by
  induction' l with hd tl IH
  · simp
  · simpa using (degree_mul_le _ _).trans (add_le_add_left IH _)
#align polynomial.degree_list_prod_le Polynomial.degree_list_prod_le
-/

/- warning: polynomial.coeff_list_prod_of_nat_degree_le -> Polynomial.coeff_list_prod_of_natDegree_le is a dubious translation:
lean 3 declaration is
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)) (n : Nat), (forall (p : Polynomial.{u1} S _inst_1), (Membership.Mem.{u1, u1} (Polynomial.{u1} S _inst_1) (List.{u1} (Polynomial.{u1} S _inst_1)) (List.hasMem.{u1} (Polynomial.{u1} S _inst_1)) p l) -> (LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u1} S _inst_1 p) n)) -> (Eq.{succ u1} S (Polynomial.coeff.{u1} S _inst_1 (List.prod.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.mul'.{u1} S _inst_1) (Polynomial.hasOne.{u1} S _inst_1) l) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (List.length.{u1} (Polynomial.{u1} S _inst_1) l) n)) (List.prod.{u1} S (Distrib.toHasMul.{u1} S (NonUnitalNonAssocSemiring.toDistrib.{u1} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (Semiring.toNonAssocSemiring.{u1} S _inst_1)))) (AddMonoidWithOne.toOne.{u1} S (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} S (NonAssocSemiring.toAddCommMonoidWithOne.{u1} S (Semiring.toNonAssocSemiring.{u1} S _inst_1)))) (List.map.{u1, u1} (Polynomial.{u1} S _inst_1) S (fun (p : Polynomial.{u1} S _inst_1) => Polynomial.coeff.{u1} S _inst_1 p n) l)))
but is expected to have type
  forall {S : Type.{u1}} [_inst_1 : Semiring.{u1} S] (l : List.{u1} (Polynomial.{u1} S _inst_1)) (n : Nat), (forall (p : Polynomial.{u1} S _inst_1), (Membership.mem.{u1, u1} (Polynomial.{u1} S _inst_1) (List.{u1} (Polynomial.{u1} S _inst_1)) (List.instMembershipList.{u1} (Polynomial.{u1} S _inst_1)) p l) -> (LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} S _inst_1 p) n)) -> (Eq.{succ u1} S (Polynomial.coeff.{u1} S _inst_1 (List.prod.{u1} (Polynomial.{u1} S _inst_1) (Polynomial.mul'.{u1} S _inst_1) (Polynomial.one.{u1} S _inst_1) l) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (List.length.{u1} (Polynomial.{u1} S _inst_1) l) n)) (List.prod.{u1} S (NonUnitalNonAssocSemiring.toMul.{u1} S (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} S (Semiring.toNonAssocSemiring.{u1} S _inst_1))) (Semiring.toOne.{u1} S _inst_1) (List.map.{u1, u1} (Polynomial.{u1} S _inst_1) S (fun (p : Polynomial.{u1} S _inst_1) => Polynomial.coeff.{u1} S _inst_1 p n) l)))
Case conversion may be inaccurate. Consider using '#align polynomial.coeff_list_prod_of_nat_degree_le Polynomial.coeff_list_prod_of_natDegree_leₓ'. -/
theorem coeff_list_prod_of_natDegree_le (l : List S[X]) (n : ℕ) (hl : ∀ p ∈ l, natDegree p ≤ n) :
    coeff (List.prod l) (l.length * n) = (l.map fun p => coeff p n).Prod :=
  by
  induction' l with hd tl IH
  · simp
  · have hl' : ∀ p ∈ tl, nat_degree p ≤ n := fun p hp => hl p (List.mem_cons_of_mem _ hp)
    simp only [List.prod_cons, List.map, List.length]
    rw [add_mul, one_mul, add_comm, ← IH hl', mul_comm tl.length]
    have h : nat_degree tl.prod ≤ n * tl.length :=
      by
      refine' (nat_degree_list_prod_le _).trans _
      rw [← tl.length_map nat_degree, mul_comm]
      refine' List.sum_le_card_nsmul _ _ _
      simpa using hl'
    have hdn : nat_degree hd ≤ n := hl _ (List.mem_cons_self _ _)
    rcases hdn.eq_or_lt with (rfl | hdn')
    · cases' h.eq_or_lt with h' h'
      · rw [← h', coeff_mul_degree_add_degree, leading_coeff, leading_coeff]
      · rw [coeff_eq_zero_of_nat_degree_lt, coeff_eq_zero_of_nat_degree_lt h',
          MulZeroClass.mul_zero]
        exact nat_degree_mul_le.trans_lt (add_lt_add_left h' _)
    · rw [coeff_eq_zero_of_nat_degree_lt hdn', coeff_eq_zero_of_nat_degree_lt,
        MulZeroClass.zero_mul]
      exact nat_degree_mul_le.trans_lt (add_lt_add_of_lt_of_le hdn' h)
#align polynomial.coeff_list_prod_of_nat_degree_le Polynomial.coeff_list_prod_of_natDegree_le

end Semiring

section CommSemiring

variable [CommSemiring R] (f : ι → R[X]) (t : Multiset R[X])

#print Polynomial.natDegree_multiset_prod_le /-
theorem natDegree_multiset_prod_le : t.Prod.natDegree ≤ (t.map natDegree).Sum :=
  Quotient.inductionOn t (by simpa using nat_degree_list_prod_le)
#align polynomial.nat_degree_multiset_prod_le Polynomial.natDegree_multiset_prod_le
-/

#print Polynomial.natDegree_prod_le /-
theorem natDegree_prod_le : (∏ i in s, f i).natDegree ≤ ∑ i in s, (f i).natDegree := by
  simpa using nat_degree_multiset_prod_le (s.1.map f)
#align polynomial.nat_degree_prod_le Polynomial.natDegree_prod_le
-/

#print Polynomial.degree_multiset_prod_le /-
/-- The degree of a product of polynomials is at most the sum of the degrees,
where the degree of the zero polynomial is ⊥.
-/
theorem degree_multiset_prod_le : t.Prod.degree ≤ (t.map Polynomial.degree).Sum :=
  Quotient.inductionOn t (by simpa using degree_list_prod_le)
#align polynomial.degree_multiset_prod_le Polynomial.degree_multiset_prod_le
-/

#print Polynomial.degree_prod_le /-
theorem degree_prod_le : (∏ i in s, f i).degree ≤ ∑ i in s, (f i).degree := by
  simpa only [Multiset.map_map] using degree_multiset_prod_le (s.1.map f)
#align polynomial.degree_prod_le Polynomial.degree_prod_le
-/

/- warning: polynomial.leading_coeff_multiset_prod' -> Polynomial.leadingCoeff_multiset_prod' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))))) -> (Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))))) -> (Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)))
Case conversion may be inaccurate. Consider using '#align polynomial.leading_coeff_multiset_prod' Polynomial.leadingCoeff_multiset_prod'ₓ'. -/
/-- The leading coefficient of a product of polynomials is equal to
the product of the leading coefficients, provided that this product is nonzero.

See `polynomial.leading_coeff_multiset_prod` (without the `'`) for a version for integral domains,
where this condition is automatically satisfied.
-/
theorem leadingCoeff_multiset_prod' (h : (t.map leadingCoeff).Prod ≠ 0) :
    t.Prod.leadingCoeff = (t.map leadingCoeff).Prod :=
  by
  induction' t using Multiset.induction_on with a t ih; · simp
  simp only [Multiset.map_cons, Multiset.prod_cons] at h⊢
  rw [Polynomial.leadingCoeff_mul'] <;>
    · rwa [ih]
      apply right_ne_zero_of_mul h
#align polynomial.leading_coeff_multiset_prod' Polynomial.leadingCoeff_multiset_prod'

/- warning: polynomial.leading_coeff_prod' -> Polynomial.leadingCoeff_prod' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))))) -> (Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))))) -> (Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
Case conversion may be inaccurate. Consider using '#align polynomial.leading_coeff_prod' Polynomial.leadingCoeff_prod'ₓ'. -/
/-- The leading coefficient of a product of polynomials is equal to
the product of the leading coefficients, provided that this product is nonzero.

See `polynomial.leading_coeff_prod` (without the `'`) for a version for integral domains,
where this condition is automatically satisfied.
-/
theorem leadingCoeff_prod' (h : (∏ i in s, (f i).leadingCoeff) ≠ 0) :
    (∏ i in s, f i).leadingCoeff = ∏ i in s, (f i).leadingCoeff := by
  simpa using leading_coeff_multiset_prod' (s.1.map f) (by simpa using h)
#align polynomial.leading_coeff_prod' Polynomial.leadingCoeff_prod'

/- warning: polynomial.nat_degree_multiset_prod' -> Polynomial.natDegree_multiset_prod' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t)) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} Nat Nat.addCommMonoid (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) Nat (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t)) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} Nat Nat.addCommMonoid (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) Nat (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t)))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_multiset_prod' Polynomial.natDegree_multiset_prod'ₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees, provided that the product of leading coefficients is nonzero.

See `polynomial.nat_degree_multiset_prod` (without the `'`) for a version for integral domains,
where this condition is automatically satisfied.
-/
theorem natDegree_multiset_prod' (h : (t.map fun f => leadingCoeff f).Prod ≠ 0) :
    t.Prod.natDegree = (t.map fun f => natDegree f).Sum :=
  by
  revert h
  refine' Multiset.induction_on t _ fun a t ih ht => _; · simp
  rw [Multiset.map_cons, Multiset.prod_cons] at ht⊢
  rw [Multiset.sum_cons, Polynomial.natDegree_mul', ih]
  · apply right_ne_zero_of_mul ht
  · rwa [Polynomial.leadingCoeff_multiset_prod']
    apply right_ne_zero_of_mul ht
#align polynomial.nat_degree_multiset_prod' Polynomial.natDegree_multiset_prod'

/- warning: polynomial.nat_degree_prod' -> Polynomial.natDegree_prod' is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))) (OfNat.ofNat.{u1} R 0 (OfNat.mk.{u1} R 0 (Zero.zero.{u1} R (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} Nat ι Nat.addCommMonoid s (fun (i : ι) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Ne.{succ u1} R (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))) (OfNat.ofNat.{u1} R 0 (Zero.toOfNat0.{u1} R (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} Nat ι Nat.addCommMonoid s (fun (i : ι) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_prod' Polynomial.natDegree_prod'ₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees, provided that the product of leading coefficients is nonzero.

See `polynomial.nat_degree_prod` (without the `'`) for a version for integral domains,
where this condition is automatically satisfied.
-/
theorem natDegree_prod' (h : (∏ i in s, (f i).leadingCoeff) ≠ 0) :
    (∏ i in s, f i).natDegree = ∑ i in s, (f i).natDegree := by
  simpa using nat_degree_multiset_prod' (s.1.map f) (by simpa using h)
#align polynomial.nat_degree_prod' Polynomial.natDegree_prod'

#print Polynomial.natDegree_multiset_prod_of_monic /-
theorem natDegree_multiset_prod_of_monic (h : ∀ f ∈ t, Monic f) :
    t.Prod.natDegree = (t.map natDegree).Sum :=
  by
  nontriviality R
  apply nat_degree_multiset_prod'
  suffices (t.map fun f => leading_coeff f).Prod = 1
    by
    rw [this]
    simp
  convert prod_replicate t.card (1 : R)
  · simp only [eq_replicate, Multiset.card_map, eq_self_iff_true, true_and_iff]
    rintro i hi
    obtain ⟨i, hi, rfl⟩ := multiset.mem_map.mp hi
    apply h
    assumption
  · simp
#align polynomial.nat_degree_multiset_prod_of_monic Polynomial.natDegree_multiset_prod_of_monic
-/

#print Polynomial.natDegree_prod_of_monic /-
theorem natDegree_prod_of_monic (h : ∀ i ∈ s, (f i).Monic) :
    (∏ i in s, f i).natDegree = ∑ i in s, (f i).natDegree := by
  simpa using nat_degree_multiset_prod_of_monic (s.1.map f) (by simpa using h)
#align polynomial.nat_degree_prod_of_monic Polynomial.natDegree_prod_of_monic
-/

/- warning: polynomial.coeff_multiset_prod_of_nat_degree_le -> Polynomial.coeff_multiset_prod_of_natDegree_le is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (n : Nat), (forall (p : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)), (Membership.Mem.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.hasMem.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) p t) -> (LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) p) n)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (coeFn.{succ u1, succ u1} (AddMonoidHom.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.orderedCancelAddCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (fun (_x : AddMonoidHom.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.orderedCancelAddCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) => (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) -> Nat) (AddMonoidHom.hasCoeToFun.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.orderedCancelAddCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.card.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) t) n)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (p : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.coeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) p n) t)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (n : Nat), (forall (p : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)), (Membership.mem.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instMembershipMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) p t) -> (LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) p) n)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t) (HMul.hMul.{0, 0, 0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) => Nat) t) Nat ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) => Nat) t) (instHMul.{0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) => Nat) t) instMulNat) (FunLike.coe.{succ u1, succ u1, 1} (AddMonoidHom.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (fun (_x : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) => Nat) _x) (AddHomClass.toFunLike.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddZeroClass.toAdd.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))))) (AddZeroClass.toAdd.{0} Nat (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (AddMonoidHomClass.toAddHomClass.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid) (AddMonoidHom.addMonoidHomClass.{u1, 0} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)))) (Multiset.card.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) t) n)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (p : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.coeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) p n) t)))
Case conversion may be inaccurate. Consider using '#align polynomial.coeff_multiset_prod_of_nat_degree_le Polynomial.coeff_multiset_prod_of_natDegree_leₓ'. -/
theorem coeff_multiset_prod_of_natDegree_le (n : ℕ) (hl : ∀ p ∈ t, natDegree p ≤ n) :
    coeff t.Prod (t.card * n) = (t.map fun p => coeff p n).Prod :=
  by
  induction t using Quotient.inductionOn
  simpa using coeff_list_prod_of_nat_degree_le _ _ hl
#align polynomial.coeff_multiset_prod_of_nat_degree_le Polynomial.coeff_multiset_prod_of_natDegree_le

#print Polynomial.coeff_prod_of_natDegree_le /-
theorem coeff_prod_of_natDegree_le (f : ι → R[X]) (n : ℕ) (h : ∀ p ∈ s, natDegree (f p) ≤ n) :
    coeff (∏ i in s, f i) (s.card * n) = ∏ i in s, coeff (f i) n :=
  by
  cases' s with l hl
  convert coeff_multiset_prod_of_nat_degree_le (l.map f) _ _
  · simp
  · simp
  · simpa using h
#align polynomial.coeff_prod_of_nat_degree_le Polynomial.coeff_prod_of_natDegree_le
-/

#print Polynomial.coeff_zero_multiset_prod /-
theorem coeff_zero_multiset_prod : t.Prod.coeff 0 = (t.map fun f => coeff f 0).Prod :=
  by
  refine' Multiset.induction_on t _ fun a t ht => _; · simp
  rw [Multiset.prod_cons, Multiset.map_cons, Multiset.prod_cons, Polynomial.mul_coeff_zero, ht]
#align polynomial.coeff_zero_multiset_prod Polynomial.coeff_zero_multiset_prod
-/

#print Polynomial.coeff_zero_prod /-
theorem coeff_zero_prod : (∏ i in s, f i).coeff 0 = ∏ i in s, (f i).coeff 0 := by
  simpa using coeff_zero_multiset_prod (s.1.map f)
#align polynomial.coeff_zero_prod Polynomial.coeff_zero_prod
-/

end CommSemiring

section CommRing

variable [CommRing R]

open Monic

/- warning: polynomial.multiset_prod_X_sub_C_next_coeff -> Polynomial.multiset_prod_X_sub_C_nextCoeff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommRing.{u1} R] (t : Multiset.{u1} R), Eq.{succ u1} R (Polynomial.nextCoeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.prod.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) (Multiset.map.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (fun (x : R) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (coeFn.{succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (fun (_x : RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) => R -> (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.hasCoeToFun.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x)) t))) (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (Multiset.sum.{u1} R (AddCommGroup.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) t))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommRing.{u1} R] (t : Multiset.{u1} R), Eq.{succ u1} R (Polynomial.nextCoeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.prod.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) (Multiset.map.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (fun (x : R) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (FunLike.coe.{succ u1, succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) _x) (MulHomClass.toFunLike.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (NonUnitalNonAssocSemiring.toMul.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (NonUnitalRingHomClass.toMulHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (RingHomClass.toNonUnitalRingHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.instRingHomClassRingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x)) t))) (Neg.neg.{u1} R (Ring.toNeg.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.sum.{u1} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) t))
Case conversion may be inaccurate. Consider using '#align polynomial.multiset_prod_X_sub_C_next_coeff Polynomial.multiset_prod_X_sub_C_nextCoeffₓ'. -/
-- Eventually this can be generalized with Vieta's formulas
-- plus the connection between roots and factorization.
theorem multiset_prod_X_sub_C_nextCoeff (t : Multiset R) :
    nextCoeff (t.map fun x => X - C x).Prod = -t.Sum :=
  by
  rw [next_coeff_multiset_prod]
  · simp only [next_coeff_X_sub_C]
    exact t.sum_hom (-AddMonoidHom.id R)
  · intros
    apply monic_X_sub_C
#align polynomial.multiset_prod_X_sub_C_next_coeff Polynomial.multiset_prod_X_sub_C_nextCoeff

/- warning: polynomial.prod_X_sub_C_next_coeff -> Polynomial.prod_x_sub_c_nextCoeff is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} [_inst_1 : CommRing.{u1} R] {s : Finset.{u2} ι} (f : ι -> R), Eq.{succ u1} R (Polynomial.nextCoeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.prod.{u1, u2} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ι (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) s (fun (i : ι) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (coeFn.{succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (fun (_x : RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) => R -> (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.hasCoeToFun.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i))))) (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (Finset.sum.{u1, u2} R ι (AddCommGroup.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) s (fun (i : ι) => f i)))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} [_inst_1 : CommRing.{u1} R] {s : Finset.{u2} ι} (f : ι -> R), Eq.{succ u1} R (Polynomial.nextCoeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.prod.{u1, u2} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ι (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) s (fun (i : ι) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i)) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (FunLike.coe.{succ u1, succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) _x) (MulHomClass.toFunLike.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (NonUnitalNonAssocSemiring.toMul.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (NonUnitalRingHomClass.toMulHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (RingHomClass.toNonUnitalRingHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.instRingHomClassRingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i))))) (Neg.neg.{u1} R (Ring.toNeg.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.sum.{u1, u2} R ι (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) s (fun (i : ι) => f i)))
Case conversion may be inaccurate. Consider using '#align polynomial.prod_X_sub_C_next_coeff Polynomial.prod_x_sub_c_nextCoeffₓ'. -/
theorem prod_x_sub_c_nextCoeff {s : Finset ι} (f : ι → R) :
    nextCoeff (∏ i in s, X - C (f i)) = -∑ i in s, f i := by
  simpa using multiset_prod_X_sub_C_next_coeff (s.1.map f)
#align polynomial.prod_X_sub_C_next_coeff Polynomial.prod_x_sub_c_nextCoeff

/- warning: polynomial.multiset_prod_X_sub_C_coeff_card_pred -> Polynomial.multiset_prod_X_sub_C_coeff_card_pred is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommRing.{u1} R] (t : Multiset.{u1} R), (LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) (coeFn.{succ u1, succ u1} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (fun (_x : AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) => (Multiset.{u1} R) -> Nat) (AddMonoidHom.hasCoeToFun.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.card.{u1} R) t)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.prod.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) (Multiset.map.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (fun (x : R) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (coeFn.{succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (fun (_x : RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) => R -> (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.hasCoeToFun.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x)) t)) (HSub.hSub.{0, 0, 0} Nat Nat Nat (instHSub.{0} Nat Nat.hasSub) (coeFn.{succ u1, succ u1} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (fun (_x : AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) => (Multiset.{u1} R) -> Nat) (AddMonoidHom.hasCoeToFun.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.orderedCancelAddCommMonoid.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.card.{u1} R) t) (OfNat.ofNat.{0} Nat 1 (OfNat.mk.{0} Nat 1 (One.one.{0} Nat Nat.hasOne))))) (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (Multiset.sum.{u1} R (AddCommGroup.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) t)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommRing.{u1} R] (t : Multiset.{u1} R), (LT.lt.{0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) t) instLTNat (OfNat.ofNat.{0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) t) 0 (instOfNatNat 0)) (FunLike.coe.{succ u1, succ u1, 1} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) (fun (_x : Multiset.{u1} R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) _x) (AddHomClass.toFunLike.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) Nat (AddZeroClass.toAdd.{u1} (Multiset.{u1} R) (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R))))))) (AddZeroClass.toAdd.{0} Nat (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (AddMonoidHomClass.toAddHomClass.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid) (AddMonoidHom.addMonoidHomClass.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)))) (Multiset.card.{u1} R) t)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.prod.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) (Multiset.map.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (fun (x : R) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (FunLike.coe.{succ u1, succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) _x) (MulHomClass.toFunLike.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (NonUnitalNonAssocSemiring.toMul.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (NonUnitalRingHomClass.toMulHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (RingHomClass.toNonUnitalRingHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.instRingHomClassRingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) x)) t)) (HSub.hSub.{0, 0, 0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) t) Nat ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) t) (instHSub.{0} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) t) instSubNat) (FunLike.coe.{succ u1, succ u1, 1} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) (fun (_x : Multiset.{u1} R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.403 : Multiset.{u1} R) => Nat) _x) (AddHomClass.toFunLike.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) Nat (AddZeroClass.toAdd.{u1} (Multiset.{u1} R) (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R))))))) (AddZeroClass.toAdd.{0} Nat (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (AddMonoidHomClass.toAddHomClass.{u1, u1, 0} (AddMonoidHom.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)) (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid) (AddMonoidHom.addMonoidHomClass.{u1, 0} (Multiset.{u1} R) Nat (AddMonoid.toAddZeroClass.{u1} (Multiset.{u1} R) (AddRightCancelMonoid.toAddMonoid.{u1} (Multiset.{u1} R) (AddCancelMonoid.toAddRightCancelMonoid.{u1} (Multiset.{u1} R) (AddCancelCommMonoid.toAddCancelMonoid.{u1} (Multiset.{u1} R) (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u1} (Multiset.{u1} R) (Multiset.instOrderedCancelAddCommMonoidMultiset.{u1} R)))))) (AddMonoid.toAddZeroClass.{0} Nat Nat.addMonoid)))) (Multiset.card.{u1} R) t) (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)))) (Neg.neg.{u1} R (Ring.toNeg.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Multiset.sum.{u1} R (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) t)))
Case conversion may be inaccurate. Consider using '#align polynomial.multiset_prod_X_sub_C_coeff_card_pred Polynomial.multiset_prod_X_sub_C_coeff_card_predₓ'. -/
theorem multiset_prod_X_sub_C_coeff_card_pred (t : Multiset R) (ht : 0 < t.card) :
    (t.map fun x => X - C x).Prod.coeff (t.card - 1) = -t.Sum :=
  by
  nontriviality R
  convert multiset_prod_X_sub_C_next_coeff (by assumption)
  rw [next_coeff]; split_ifs
  · rw [nat_degree_multiset_prod_of_monic] at h <;> simp only [Multiset.mem_map] at *
    swap
    · rintro _ ⟨_, _, rfl⟩
      apply monic_X_sub_C
    simp_rw [Multiset.sum_eq_zero_iff, Multiset.mem_map] at h
    contrapose! h
    obtain ⟨x, hx⟩ := card_pos_iff_exists_mem.mp ht
    exact ⟨_, ⟨_, ⟨x, hx, rfl⟩, nat_degree_X_sub_C _⟩, one_ne_zero⟩
  congr ; rw [nat_degree_multiset_prod_of_monic] <;> · simp [nat_degree_X_sub_C, monic_X_sub_C]
#align polynomial.multiset_prod_X_sub_C_coeff_card_pred Polynomial.multiset_prod_X_sub_C_coeff_card_pred

/- warning: polynomial.prod_X_sub_C_coeff_card_pred -> Polynomial.prod_X_sub_C_coeff_card_pred is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} [_inst_1 : CommRing.{u1} R] (s : Finset.{u2} ι) (f : ι -> R), (LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) (Finset.card.{u2} ι s)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.prod.{u1, u2} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ι (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) s (fun (i : ι) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (coeFn.{succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (fun (_x : RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) => R -> (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.hasCoeToFun.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i)))) (HSub.hSub.{0, 0, 0} Nat Nat Nat (instHSub.{0} Nat Nat.hasSub) (Finset.card.{u2} ι s) (OfNat.ofNat.{0} Nat 1 (OfNat.mk.{0} Nat 1 (One.one.{0} Nat Nat.hasOne))))) (Neg.neg.{u1} R (SubNegMonoid.toHasNeg.{u1} R (AddGroup.toSubNegMonoid.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (Finset.sum.{u1, u2} R ι (AddCommGroup.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) s (fun (i : ι) => f i))))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} [_inst_1 : CommRing.{u1} R] (s : Finset.{u2} ι) (f : ι -> R), (LT.lt.{0} Nat instLTNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) (Finset.card.{u2} ι s)) -> (Eq.{succ u1} R (Polynomial.coeff.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.prod.{u1, u2} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ι (CommRing.toCommMonoid.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.commRing.{u1} R _inst_1)) s (fun (i : ι) => HSub.hSub.{u1, u1, u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i)) (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (instHSub.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.sub.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.X.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (FunLike.coe.{succ u1, succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) _x) (MulHomClass.toFunLike.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (NonUnitalNonAssocSemiring.toMul.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))) (NonUnitalRingHomClass.toMulHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (RingHomClass.toNonUnitalRingHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))))) R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))) (RingHom.instRingHomClassRingHom.{u1, u1} R (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (Polynomial.semiring.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)))))))) (Polynomial.C.{u1} R (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1))) (f i)))) (HSub.hSub.{0, 0, 0} Nat Nat Nat (instHSub.{0} Nat instSubNat) (Finset.card.{u2} ι s) (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)))) (Neg.neg.{u1} R (Ring.toNeg.{u1} R (CommRing.toRing.{u1} R _inst_1)) (Finset.sum.{u1, u2} R ι (NonUnitalNonAssocSemiring.toAddCommMonoid.{u1} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (CommRing.toRing.{u1} R _inst_1))))) s (fun (i : ι) => f i))))
Case conversion may be inaccurate. Consider using '#align polynomial.prod_X_sub_C_coeff_card_pred Polynomial.prod_X_sub_C_coeff_card_predₓ'. -/
theorem prod_X_sub_C_coeff_card_pred (s : Finset ι) (f : ι → R) (hs : 0 < s.card) :
    (∏ i in s, X - C (f i)).coeff (s.card - 1) = -∑ i in s, f i := by
  simpa using multiset_prod_X_sub_C_coeff_card_pred (s.1.map f) (by simpa using hs)
#align polynomial.prod_X_sub_C_coeff_card_pred Polynomial.prod_X_sub_C_coeff_card_pred

end CommRing

section NoZeroDivisors

section Semiring

variable [Semiring R] [NoZeroDivisors R]

/- warning: polynomial.degree_list_prod -> Polynomial.degree_list_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))))] [_inst_3 : Nontrivial.{u1} R] (l : List.{u1} (Polynomial.{u1} R _inst_1)), Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R _inst_1 (List.prod.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.mul'.{u1} R _inst_1) (Polynomial.hasOne.{u1} R _inst_1) l)) (List.sum.{0} (WithBot.{0} Nat) (WithBot.hasAdd.{0} Nat Nat.hasAdd) (WithBot.hasZero.{0} Nat Nat.hasZero) (List.map.{u1, 0} (Polynomial.{u1} R _inst_1) (WithBot.{0} Nat) (Polynomial.degree.{u1} R _inst_1) l))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : Semiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))) (MonoidWithZero.toZero.{u1} R (Semiring.toMonoidWithZero.{u1} R _inst_1))] [_inst_3 : Nontrivial.{u1} R] (l : List.{u1} (Polynomial.{u1} R _inst_1)), Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R _inst_1 (List.prod.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.mul'.{u1} R _inst_1) (Polynomial.one.{u1} R _inst_1) l)) (List.sum.{0} (WithBot.{0} Nat) (WithBot.add.{0} Nat instAddNat) (WithBot.zero.{0} Nat (LinearOrderedCommMonoidWithZero.toZero.{0} Nat Nat.linearOrderedCommMonoidWithZero)) (List.map.{u1, 0} (Polynomial.{u1} R _inst_1) (WithBot.{0} Nat) (Polynomial.degree.{u1} R _inst_1) l))
Case conversion may be inaccurate. Consider using '#align polynomial.degree_list_prod Polynomial.degree_list_prodₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees, where the degree of the zero polynomial is ⊥.
`[nontrivial R]` is needed, otherwise for `l = []` we have `⊥` in the LHS and `0` in the RHS.
-/
theorem degree_list_prod [Nontrivial R] (l : List R[X]) : l.Prod.degree = (l.map degree).Sum :=
  map_list_prod (@degreeMonoidHom R _ _ _) l
#align polynomial.degree_list_prod Polynomial.degree_list_prod

end Semiring

section CommSemiring

variable [CommSemiring R] [NoZeroDivisors R] (f : ι → R[X]) (t : Multiset R[X])

/- warning: polynomial.nat_degree_prod -> Polynomial.natDegree_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (forall (i : ι), (Membership.Mem.{u2, u2} ι (Finset.{u2} ι) (Finset.hasMem.{u2} ι) i s) -> (Ne.{succ u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (f i) (OfNat.ofNat.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (OfNat.mk.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (Zero.zero.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.zero.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} Nat ι Nat.addCommMonoid s (fun (i : ι) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (forall (i : ι), (Membership.mem.{u2, u2} ι (Finset.{u2} ι) (Finset.instMembershipFinset.{u2} ι) i s) -> (Ne.{succ u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (f i) (OfNat.ofNat.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (Zero.toOfNat0.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.zero.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} Nat ι Nat.addCommMonoid s (fun (i : ι) => Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i))))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_prod Polynomial.natDegree_prodₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees.

See `polynomial.nat_degree_prod'` (with a `'`) for a version for commutative semirings,
where additionally, the product of the leading coefficients must be nonzero.
-/
theorem natDegree_prod (h : ∀ i ∈ s, f i ≠ 0) :
    (∏ i in s, f i).natDegree = ∑ i in s, (f i).natDegree :=
  by
  nontriviality R
  apply nat_degree_prod'
  rw [prod_ne_zero_iff]
  intro x hx; simp [h x hx]
#align polynomial.nat_degree_prod Polynomial.natDegree_prod

/- warning: polynomial.nat_degree_multiset_prod -> Polynomial.natDegree_multiset_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Not (Membership.Mem.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.hasMem.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OfNat.ofNat.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (OfNat.mk.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (Zero.zero.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.zero.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) t)) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} Nat Nat.addCommMonoid (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), (Not (Membership.mem.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (Multiset.instMembershipMultiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) (OfNat.ofNat.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) 0 (Zero.toOfNat0.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.zero.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) t)) -> (Eq.{1} Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} Nat Nat.addCommMonoid (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) Nat (Polynomial.natDegree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) t)))
Case conversion may be inaccurate. Consider using '#align polynomial.nat_degree_multiset_prod Polynomial.natDegree_multiset_prodₓ'. -/
theorem natDegree_multiset_prod (h : (0 : R[X]) ∉ t) : natDegree t.Prod = (t.map natDegree).Sum :=
  by
  nontriviality R
  rw [nat_degree_multiset_prod']
  simp_rw [Ne.def, Multiset.prod_eq_zero_iff, Multiset.mem_map, leading_coeff_eq_zero]
  rintro ⟨_, h, rfl⟩
  contradiction
#align polynomial.nat_degree_multiset_prod Polynomial.natDegree_multiset_prod

/- warning: polynomial.degree_multiset_prod -> Polynomial.degree_multiset_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) [_inst_3 : Nontrivial.{u1} R], Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} (WithBot.{0} Nat) (WithBot.addCommMonoid.{0} Nat Nat.addCommMonoid) (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (WithBot.{0} Nat) (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) [_inst_3 : Nontrivial.{u1} R], Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.sum.{0} (WithBot.{0} Nat) (WithBot.addCommMonoid.{0} Nat Nat.addCommMonoid) (Multiset.map.{u1, 0} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (WithBot.{0} Nat) (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t))
Case conversion may be inaccurate. Consider using '#align polynomial.degree_multiset_prod Polynomial.degree_multiset_prodₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees, where the degree of the zero polynomial is ⊥.
-/
theorem degree_multiset_prod [Nontrivial R] : t.Prod.degree = (t.map fun f => degree f).Sum :=
  map_multiset_prod (@degreeMonoidHom R _ _ _) _
#align polynomial.degree_multiset_prod Polynomial.degree_multiset_prod

/- warning: polynomial.degree_prod -> Polynomial.degree_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) [_inst_3 : Nontrivial.{u1} R], Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} (WithBot.{0} Nat) ι (WithBot.addCommMonoid.{0} Nat Nat.addCommMonoid) s (fun (i : ι) => Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i)))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))) [_inst_3 : Nontrivial.{u1} R], Eq.{1} (WithBot.{0} Nat) (Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.sum.{0, u2} (WithBot.{0} Nat) ι (WithBot.addCommMonoid.{0} Nat Nat.addCommMonoid) s (fun (i : ι) => Polynomial.degree.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i)))
Case conversion may be inaccurate. Consider using '#align polynomial.degree_prod Polynomial.degree_prodₓ'. -/
/-- The degree of a product of polynomials is equal to
the sum of the degrees, where the degree of the zero polynomial is ⊥.
-/
theorem degree_prod [Nontrivial R] : (∏ i in s, f i).degree = ∑ i in s, (f i).degree :=
  map_prod (@degreeMonoidHom R _ _ _) _ _
#align polynomial.degree_prod Polynomial.degree_prod

/- warning: polynomial.leading_coeff_multiset_prod -> Polynomial.leadingCoeff_multiset_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (t : Multiset.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Multiset.prod.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) t)) (Multiset.prod.{u1} R (CommSemiring.toCommMonoid.{u1} R _inst_1) (Multiset.map.{u1, u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) R (fun (f : Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) f) t))
Case conversion may be inaccurate. Consider using '#align polynomial.leading_coeff_multiset_prod Polynomial.leadingCoeff_multiset_prodₓ'. -/
/-- The leading coefficient of a product of polynomials is equal to
the product of the leading coefficients.

See `polynomial.leading_coeff_multiset_prod'` (with a `'`) for a version for commutative semirings,
where additionally, the product of the leading coefficients must be nonzero.
-/
theorem leadingCoeff_multiset_prod : t.Prod.leadingCoeff = (t.map fun f => leadingCoeff f).Prod :=
  by
  rw [← leading_coeff_hom_apply, MonoidHom.map_multiset_prod]
  rfl
#align polynomial.leading_coeff_multiset_prod Polynomial.leadingCoeff_multiset_prod

/- warning: polynomial.leading_coeff_prod -> Polynomial.leadingCoeff_prod is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (Distrib.toHasMul.{u1} R (NonUnitalNonAssocSemiring.toDistrib.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))))) (MulZeroClass.toHasZero.{u1} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i)))
but is expected to have type
  forall {R : Type.{u1}} {ι : Type.{u2}} (s : Finset.{u2} ι) [_inst_1 : CommSemiring.{u1} R] [_inst_2 : NoZeroDivisors.{u1} R (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)))) (CommMonoidWithZero.toZero.{u1} R (CommSemiring.toCommMonoidWithZero.{u1} R _inst_1))] (f : ι -> (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1))), Eq.{succ u1} R (Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (Finset.prod.{u1, u2} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) ι (CommSemiring.toCommMonoid.{u1} (Polynomial.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1)) (Polynomial.commSemiring.{u1} R _inst_1)) s (fun (i : ι) => f i))) (Finset.prod.{u1, u2} R ι (CommSemiring.toCommMonoid.{u1} R _inst_1) s (fun (i : ι) => Polynomial.leadingCoeff.{u1} R (CommSemiring.toSemiring.{u1} R _inst_1) (f i)))
Case conversion may be inaccurate. Consider using '#align polynomial.leading_coeff_prod Polynomial.leadingCoeff_prodₓ'. -/
/-- The leading coefficient of a product of polynomials is equal to
the product of the leading coefficients.

See `polynomial.leading_coeff_prod'` (with a `'`) for a version for commutative semirings,
where additionally, the product of the leading coefficients must be nonzero.
-/
theorem leadingCoeff_prod : (∏ i in s, f i).leadingCoeff = ∏ i in s, (f i).leadingCoeff := by
  simpa using leading_coeff_multiset_prod (s.1.map f)
#align polynomial.leading_coeff_prod Polynomial.leadingCoeff_prod

end CommSemiring

end NoZeroDivisors

end Polynomial