Skip to content

Commit

Permalink
refactor: split Analysis.Calculus.LocalExtr (#5944)
Browse files Browse the repository at this point in the history
Also make `f`/`f'` arguments implicit in all versions of Rolle's Theorem.

Fixes #4830

## API changes

- `exists_Ioo_extr_on_Icc`:
  - generalize from functions `f : ℝ → ℝ`
    to functions from a conditionally complete linear order
    to a linear order.
  - make `f` implicit;
- `exists_local_extr_Ioo`:
  - rename to `exists_isLocalExtr_Ioo`;
  - generalize as above;
  - make `f` implicit;
- `exists_isExtrOn_Ioo_of_tendsto`, `exists_isLocalExtr_Ioo_of_tendsto`:
  new lemmas extracted from the proof of `exists_hasDerivAt_eq_zero'`;
- `exists_hasDerivAt_eq_zero`, `exists_hasDerivAt_eq_zero'`:
  make `f` and `f'` implicit;
- `exists_deriv_eq_zero`, `exists_deriv_eq_zero'`:
  make `f` implicit.
  • Loading branch information
urkud authored and semorrison committed Aug 14, 2023
1 parent 0d650a0 commit 282e596
Show file tree
Hide file tree
Showing 16 changed files with 307 additions and 175 deletions.
2 changes: 1 addition & 1 deletion Archive/Wiedijk100Theorems/AbelRuffini.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Copyright (c) 2021 Thomas Browning. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Thomas Browning
-/
import Mathlib.Analysis.Calculus.LocalExtr
import Mathlib.Analysis.Calculus.LocalExtr.Polynomial
import Mathlib.FieldTheory.AbelRuffini
import Mathlib.RingTheory.RootsOfUnity.Minpoly
import Mathlib.RingTheory.EisensteinCriterion
Expand Down
5 changes: 4 additions & 1 deletion Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,9 @@ import Mathlib.Analysis.Calculus.Inverse
import Mathlib.Analysis.Calculus.IteratedDeriv
import Mathlib.Analysis.Calculus.LHopital
import Mathlib.Analysis.Calculus.LagrangeMultipliers
import Mathlib.Analysis.Calculus.LocalExtr
import Mathlib.Analysis.Calculus.LocalExtr.Basic
import Mathlib.Analysis.Calculus.LocalExtr.Polynomial
import Mathlib.Analysis.Calculus.LocalExtr.Rolle
import Mathlib.Analysis.Calculus.MeanValue
import Mathlib.Analysis.Calculus.Monotone
import Mathlib.Analysis.Calculus.ParametricIntegral
Expand Down Expand Up @@ -3134,6 +3136,7 @@ import Mathlib.Topology.Algebra.Order.LiminfLimsup
import Mathlib.Topology.Algebra.Order.MonotoneContinuity
import Mathlib.Topology.Algebra.Order.MonotoneConvergence
import Mathlib.Topology.Algebra.Order.ProjIcc
import Mathlib.Topology.Algebra.Order.Rolle
import Mathlib.Topology.Algebra.Order.T5
import Mathlib.Topology.Algebra.Order.UpperLower
import Mathlib.Topology.Algebra.Polynomial
Expand Down
4 changes: 3 additions & 1 deletion Mathlib/Analysis/Calculus/Darboux.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Copyright (c) 2020 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Analysis.Calculus.LocalExtr
import Mathlib.Analysis.Calculus.Deriv.Add
import Mathlib.Analysis.Calculus.Deriv.Mul
import Mathlib.Analysis.Calculus.LocalExtr.Basic

#align_import analysis.calculus.darboux from "leanprover-community/mathlib"@"61b5e2755ccb464b68d05a9acf891ae04992d09d"

Expand Down
1 change: 1 addition & 0 deletions Mathlib/Analysis/Calculus/FDerivSymmetric.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Copyright (c) 2021 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
import Mathlib.Analysis.Calculus.Deriv.Pow
import Mathlib.Analysis.Calculus.MeanValue

#align_import analysis.calculus.fderiv_symmetric from "leanprover-community/mathlib"@"2c1d8ca2812b64f88992a5294ea3dba144755cd1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ Copyright (c) 2019 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov
-/
import Mathlib.Analysis.Calculus.Deriv.Polynomial
import Mathlib.Topology.Algebra.Order.ExtendFrom
import Mathlib.Topology.Algebra.Polynomial
import Mathlib.Analysis.Calculus.Deriv.Add

#align_import analysis.calculus.local_extr from "leanprover-community/mathlib"@"3bce8d800a6f2b8f63fe1e588fd76a9ff4adcebe"

/-!
# Local extrema of smooth functions
# Local extrema of differentiable functions
## Main definitions
Expand All @@ -24,7 +22,7 @@ This set is used in the proof of Fermat's Theorem (see below), and can be used t
For each theorem name listed below,
we also prove similar theorems for `min`, `extr` (if applicable),
and `(f)deriv` instead of `has_fderiv`.
and `fderiv`/`deriv` instead of `HasFDerivAt`/`HasDerivAt`.
* `IsLocalMaxOn.hasFDerivWithinAt_nonpos` : `f' y ≤ 0` whenever `a` is a local maximum
of `f` on `s`, `f` has derivative `f'` at `a` within `s`, and `y` belongs to the positive tangent
Expand All @@ -37,10 +35,6 @@ and `(f)deriv` instead of `has_fderiv`.
[Fermat's Theorem](https://en.wikipedia.org/wiki/Fermat's_theorem_(stationary_points)),
the derivative of a differentiable function at a local extremum point equals zero.
* `exists_hasDerivAt_eq_zero` :
[Rolle's Theorem](https://en.wikipedia.org/wiki/Rolle's_theorem): given a function `f` continuous
on `[a, b]` and differentiable on `(a, b)`, there exists `c ∈ (a, b)` such that `f' c = 0`.
## Implementation notes
For each mathematical fact we prove several versions of its formalization:
Expand All @@ -54,25 +48,28 @@ due to the fact that `fderiv` and `deriv` are defined to be zero for non-differe
## References
* [Fermat's Theorem](https://en.wikipedia.org/wiki/Fermat's_theorem_(stationary_points));
* [Rolle's Theorem](https://en.wikipedia.org/wiki/Rolle's_theorem);
* [Tangent cone](https://en.wikipedia.org/wiki/Tangent_cone);
## Tags
local extremum, Fermat's Theorem, Rolle's Theorem
local extremum, tangent cone, Fermat's Theorem
-/


universe u v

open Filter Set

open scoped Topology Classical Polynomial
open scoped Topology Classical

section Module

variable {E : Type u} [NormedAddCommGroup E] [NormedSpace ℝ E] {f : E → ℝ} {a : E} {f' : E →L[ℝ] ℝ}

/-!
### Positive tangent cone
-/

/-- "Positive" tangent cone to `s` at `x`; the only difference from `tangentConeAt`
is that we require `c n → ∞` instead of `‖c n‖ → ∞`. One can think about `posTangentConeAt`
as `tangentConeAt NNReal` but we have no theory of normed semifields yet. -/
Expand Down Expand Up @@ -108,6 +105,10 @@ theorem posTangentConeAt_univ : posTangentConeAt univ a = univ :=
eq_univ_of_forall fun _ => mem_posTangentConeAt_of_segment_subset' (subset_univ _)
#align pos_tangent_cone_at_univ posTangentConeAt_univ

/-!
### Fermat's Theorem (vector space)
-/

/-- If `f` has a local max on `s` at `a`, `f'` is the derivative of `f` at `a` within `s`, and
`y` belongs to the positive tangent cone of `s` at `a`, then `f' y ≤ 0`. -/
theorem IsLocalMaxOn.hasFDerivWithinAt_nonpos {s : Set E} (h : IsLocalMaxOn f s a)
Expand Down Expand Up @@ -219,6 +220,10 @@ theorem IsLocalExtr.fderiv_eq_zero (h : IsLocalExtr f a) : fderiv ℝ f a = 0 :=

end Module

/-!
### Fermat's Theorem
-/

section Real

variable {f : ℝ → ℝ} {f' : ℝ} {a b : ℝ}
Expand Down Expand Up @@ -256,160 +261,3 @@ theorem IsLocalExtr.deriv_eq_zero (h : IsLocalExtr f a) : deriv f a = 0 :=
#align is_local_extr.deriv_eq_zero IsLocalExtr.deriv_eq_zero

end Real

section Rolle

variable (f f' : ℝ → ℝ) {a b : ℝ}

/-- A continuous function on a closed interval with `f a = f b` takes either its maximum
or its minimum value at a point in the interior of the interval. -/
theorem exists_Ioo_extr_on_Icc (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI : f a = f b) :
∃ c ∈ Ioo a b, IsExtrOn f (Icc a b) c := by
have ne : (Icc a b).Nonempty := nonempty_Icc.2 (le_of_lt hab)
-- Consider absolute min and max points
obtain ⟨c, cmem, cle⟩ : ∃ c ∈ Icc a b, ∀ x ∈ Icc a b, f c ≤ f x :=
isCompact_Icc.exists_forall_le ne hfc
obtain ⟨C, Cmem, Cge⟩ : ∃ C ∈ Icc a b, ∀ x ∈ Icc a b, f x ≤ f C :=
isCompact_Icc.exists_forall_ge ne hfc
by_cases hc : f c = f a
· by_cases hC : f C = f a
· have : ∀ x ∈ Icc a b, f x = f a := fun x hx => le_antisymm (hC ▸ Cge x hx) (hc ▸ cle x hx)
-- `f` is a constant, so we can take any point in `Ioo a b`
rcases nonempty_Ioo.2 hab with ⟨c', hc'⟩
refine ⟨c', hc', Or.inl fun x hx ↦ ?_⟩
simp only [mem_setOf_eq, this x hx, this c' (Ioo_subset_Icc_self hc'), le_rfl]
· refine' ⟨C, ⟨lt_of_le_of_ne Cmem.1 <| mt _ hC, lt_of_le_of_ne Cmem.2 <| mt _ hC⟩, Or.inr Cge⟩
exacts [fun h => by rw [h], fun h => by rw [h, hfI]]
· refine' ⟨c, ⟨lt_of_le_of_ne cmem.1 <| mt _ hc, lt_of_le_of_ne cmem.2 <| mt _ hc⟩, Or.inl cle⟩
exacts [fun h => by rw [h], fun h => by rw [h, hfI]]
#align exists_Ioo_extr_on_Icc exists_Ioo_extr_on_Icc

/-- A continuous function on a closed interval with `f a = f b` has a local extremum at some
point of the corresponding open interval. -/
theorem exists_local_extr_Ioo (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI : f a = f b) :
∃ c ∈ Ioo a b, IsLocalExtr f c :=
let ⟨c, cmem, hc⟩ := exists_Ioo_extr_on_Icc f hab hfc hfI
⟨c, cmem, hc.isLocalExtr <| Icc_mem_nhds cmem.1 cmem.2
#align exists_local_extr_Ioo exists_local_extr_Ioo

/-- **Rolle's Theorem** `HasDerivAt` version -/
theorem exists_hasDerivAt_eq_zero (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI : f a = f b)
(hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x) : ∃ c ∈ Ioo a b, f' c = 0 :=
let ⟨c, cmem, hc⟩ := exists_local_extr_Ioo f hab hfc hfI
⟨c, cmem, hc.hasDerivAt_eq_zero <| hff' c cmem⟩
#align exists_has_deriv_at_eq_zero exists_hasDerivAt_eq_zero

/-- **Rolle's Theorem** `deriv` version -/
theorem exists_deriv_eq_zero (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI : f a = f b) :
∃ c ∈ Ioo a b, deriv f c = 0 :=
let ⟨c, cmem, hc⟩ := exists_local_extr_Ioo f hab hfc hfI
⟨c, cmem, hc.deriv_eq_zero⟩
#align exists_deriv_eq_zero exists_deriv_eq_zero

variable {f f'} {l : ℝ}

/-- **Rolle's Theorem**, a version for a function on an open interval: if `f` has derivative `f'`
on `(a, b)` and has the same limit `l` at `𝓝[>] a` and `𝓝[<] b`, then `f' c = 0`
for some `c ∈ (a, b)`. -/
theorem exists_hasDerivAt_eq_zero' (hab : a < b) (hfa : Tendsto f (𝓝[>] a) (𝓝 l))
(hfb : Tendsto f (𝓝[<] b) (𝓝 l)) (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x) :
∃ c ∈ Ioo a b, f' c = 0 := by
have : ContinuousOn f (Ioo a b) := fun x hx => (hff' x hx).continuousAt.continuousWithinAt
have hcont := continuousOn_Icc_extendFrom_Ioo hab.ne this hfa hfb
obtain ⟨c, hc, hcextr⟩ : ∃ c ∈ Ioo a b, IsLocalExtr (extendFrom (Ioo a b) f) c := by
apply exists_local_extr_Ioo _ hab hcont
rw [eq_lim_at_right_extendFrom_Ioo hab hfb]
exact eq_lim_at_left_extendFrom_Ioo hab hfa
use c, hc
apply (hcextr.congr _).hasDerivAt_eq_zero (hff' c hc)
rw [eventuallyEq_iff_exists_mem]
exact ⟨Ioo a b, Ioo_mem_nhds hc.1 hc.2, extendFrom_extends this⟩
#align exists_has_deriv_at_eq_zero' exists_hasDerivAt_eq_zero'

/-- **Rolle's Theorem**, a version for a function on an open interval: if `f` has the same limit
`l` at `𝓝[>] a` and `𝓝[<] b`, then `deriv f c = 0` for some `c ∈ (a, b)`. This version
does not require differentiability of `f` because we define `deriv f c = 0` whenever `f` is not
differentiable at `c`. -/
theorem exists_deriv_eq_zero' (hab : a < b) (hfa : Tendsto f (𝓝[>] a) (𝓝 l))
(hfb : Tendsto f (𝓝[<] b) (𝓝 l)) : ∃ c ∈ Ioo a b, deriv f c = 0 :=
by_cases
(fun h : ∀ x ∈ Ioo a b, DifferentiableAt ℝ f x =>
show ∃ c ∈ Ioo a b, deriv f c = 0 from
exists_hasDerivAt_eq_zero' hab hfa hfb fun x hx => (h x hx).hasDerivAt)
fun h : ¬∀ x ∈ Ioo a b, DifferentiableAt ℝ f x =>
have h : ∃ x, x ∈ Ioo a b ∧ ¬DifferentiableAt ℝ f x := by push_neg at h; exact h
let ⟨c, hc, hcdiff⟩ := h
⟨c, hc, deriv_zero_of_not_differentiableAt hcdiff⟩
#align exists_deriv_eq_zero' exists_deriv_eq_zero'

end Rolle

namespace Polynomial

open scoped BigOperators

/-- The number of roots of a real polynomial `p` is at most the number of roots of its derivative
that are not roots of `p` plus one. -/
theorem card_roots_toFinset_le_card_roots_derivative_diff_roots_succ (p : ℝ[X]) :
p.roots.toFinset.card ≤ (p.derivative.roots.toFinset \ p.roots.toFinset).card + 1 := by
cases' eq_or_ne (derivative p) 0 with hp' hp'
· rw [eq_C_of_derivative_eq_zero hp', roots_C, Multiset.toFinset_zero, Finset.card_empty]
exact zero_le _
have hp : p ≠ 0 := ne_of_apply_ne derivative (by rwa [derivative_zero])
refine' Finset.card_le_diff_of_interleaved fun x hx y hy hxy hxy' => _
rw [Multiset.mem_toFinset, mem_roots hp] at hx hy
obtain ⟨z, hz1, hz2⟩ :=
exists_deriv_eq_zero (fun x : ℝ => eval x p) hxy p.continuousOn (hx.trans hy.symm)
refine' ⟨z, _, hz1⟩
rwa [Multiset.mem_toFinset, mem_roots hp', IsRoot, ← p.deriv]
#align polynomial.card_roots_to_finset_le_card_roots_derivative_diff_roots_succ Polynomial.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ

/-- The number of roots of a real polynomial is at most the number of roots of its derivative plus
one. -/
theorem card_roots_toFinset_le_derivative (p : ℝ[X]) :
p.roots.toFinset.card ≤ p.derivative.roots.toFinset.card + 1 :=
p.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ.trans <|
add_le_add_right (Finset.card_mono <| Finset.sdiff_subset _ _) _
#align polynomial.card_roots_to_finset_le_derivative Polynomial.card_roots_toFinset_le_derivative

/-- The number of roots of a real polynomial (counted with multiplicities) is at most the number of
roots of its derivative (counted with multiplicities) plus one. -/
theorem card_roots_le_derivative (p : ℝ[X]) :
Multiset.card p.roots ≤ Multiset.card (derivative p).roots + 1 :=
calc
Multiset.card p.roots = ∑ x in p.roots.toFinset, p.roots.count x :=
(Multiset.toFinset_sum_count_eq _).symm
_ = ∑ x in p.roots.toFinset, (p.roots.count x - 1 + 1) :=
(Eq.symm <| Finset.sum_congr rfl fun x hx => tsub_add_cancel_of_le <|
Nat.succ_le_iff.2 <| Multiset.count_pos.2 <| Multiset.mem_toFinset.1 hx)
_ = (∑ x in p.roots.toFinset, (p.rootMultiplicity x - 1)) + p.roots.toFinset.card := by
simp only [Finset.sum_add_distrib, Finset.card_eq_sum_ones, count_roots]
_ ≤ (∑ x in p.roots.toFinset, p.derivative.rootMultiplicity x) +
((p.derivative.roots.toFinset \ p.roots.toFinset).card + 1) :=
(add_le_add
(Finset.sum_le_sum fun x _ => rootMultiplicity_sub_one_le_derivative_rootMultiplicity _ _)
p.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ)
_ ≤ (∑ x in p.roots.toFinset, p.derivative.roots.count x) +
((∑ x in p.derivative.roots.toFinset \ p.roots.toFinset,
p.derivative.roots.count x) + 1) := by
simp only [← count_roots]
refine' add_le_add_left (add_le_add_right ((Finset.card_eq_sum_ones _).trans_le _) _) _
refine' Finset.sum_le_sum fun x hx => Nat.succ_le_iff.2 <| _
rw [Multiset.count_pos, ← Multiset.mem_toFinset]
exact (Finset.mem_sdiff.1 hx).1
_ = Multiset.card (derivative p).roots + 1 := by
rw [← add_assoc, ← Finset.sum_union Finset.disjoint_sdiff, Finset.union_sdiff_self_eq_union, ←
Multiset.toFinset_sum_count_eq, ← Finset.sum_subset (Finset.subset_union_right _ _)]
intro x _ hx₂
simpa only [Multiset.mem_toFinset, Multiset.count_eq_zero] using hx₂
#align polynomial.card_roots_le_derivative Polynomial.card_roots_le_derivative

/-- The number of real roots of a polynomial is at most the number of roots of its derivative plus
one. -/
theorem card_rootSet_le_derivative {F : Type _} [CommRing F] [Algebra F ℝ] (p : F[X]) :
Fintype.card (p.rootSet ℝ) ≤ Fintype.card (p.derivative.rootSet ℝ) + 1 := by
simpa only [rootSet_def, Finset.coe_sort_coe, Fintype.card_coe, derivative_map] using
card_roots_toFinset_le_derivative (p.map (algebraMap F ℝ))
#align polynomial.card_root_set_le_derivative Polynomial.card_rootSet_le_derivative

end Polynomial
99 changes: 99 additions & 0 deletions Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/-
Copyright (c) 2021 Benjamin Davidson. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Benjamin Davidson, Yury Kudryashov
-/
import Mathlib.Analysis.Calculus.LocalExtr.Rolle
import Mathlib.Analysis.Calculus.Deriv.Polynomial
import Mathlib.Topology.Algebra.Polynomial

#align_import analysis.calculus.local_extr from "leanprover-community/mathlib"@"3bce8d800a6f2b8f63fe1e588fd76a9ff4adcebe"

/-!
# Rolle's Theorem for polynomials
In this file we use Rolle's Theorem
to relate the number of real roots of a real polynomial and its derivative.
Namely, we prove the following facts.
* `Polynomial.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ`:
the number of roots of a real polynomial `p` is at most the number of roots of its derivative
that are not roots of `p` plus one.
* `Polynomial.card_roots_toFinset_le_derivative`, `Polynomial.card_rootSet_le_derivative`:
the number of roots of a real polynomial
is at most the number of roots of its derivative plus one.
* `Polynomial.card_roots_le_derivative`: same, but the roots are counted with multiplicities.
## Keywords
polynomial, Rolle's Theorem, root
-/

namespace Polynomial

open scoped BigOperators

/-- The number of roots of a real polynomial `p` is at most the number of roots of its derivative
that are not roots of `p` plus one. -/
theorem card_roots_toFinset_le_card_roots_derivative_diff_roots_succ (p : ℝ[X]) :
p.roots.toFinset.card ≤ (p.derivative.roots.toFinset \ p.roots.toFinset).card + 1 := by
cases' eq_or_ne (derivative p) 0 with hp' hp'
· rw [eq_C_of_derivative_eq_zero hp', roots_C, Multiset.toFinset_zero, Finset.card_empty]
exact zero_le _
have hp : p ≠ 0 := ne_of_apply_ne derivative (by rwa [derivative_zero])
refine' Finset.card_le_diff_of_interleaved fun x hx y hy hxy hxy' => _
rw [Multiset.mem_toFinset, mem_roots hp] at hx hy
obtain ⟨z, hz1, hz2⟩ := exists_deriv_eq_zero hxy p.continuousOn (hx.trans hy.symm)
refine' ⟨z, _, hz1⟩
rwa [Multiset.mem_toFinset, mem_roots hp', IsRoot, ← p.deriv]
#align polynomial.card_roots_to_finset_le_card_roots_derivative_diff_roots_succ Polynomial.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ

/-- The number of roots of a real polynomial is at most the number of roots of its derivative plus
one. -/
theorem card_roots_toFinset_le_derivative (p : ℝ[X]) :
p.roots.toFinset.card ≤ p.derivative.roots.toFinset.card + 1 :=
p.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ.trans <|
add_le_add_right (Finset.card_mono <| Finset.sdiff_subset _ _) _
#align polynomial.card_roots_to_finset_le_derivative Polynomial.card_roots_toFinset_le_derivative

/-- The number of roots of a real polynomial (counted with multiplicities) is at most the number of
roots of its derivative (counted with multiplicities) plus one. -/
theorem card_roots_le_derivative (p : ℝ[X]) :
Multiset.card p.roots ≤ Multiset.card (derivative p).roots + 1 :=
calc
Multiset.card p.roots = ∑ x in p.roots.toFinset, p.roots.count x :=
(Multiset.toFinset_sum_count_eq _).symm
_ = ∑ x in p.roots.toFinset, (p.roots.count x - 1 + 1) :=
(Eq.symm <| Finset.sum_congr rfl fun x hx => tsub_add_cancel_of_le <|
Nat.succ_le_iff.2 <| Multiset.count_pos.2 <| Multiset.mem_toFinset.1 hx)
_ = (∑ x in p.roots.toFinset, (p.rootMultiplicity x - 1)) + p.roots.toFinset.card := by
simp only [Finset.sum_add_distrib, Finset.card_eq_sum_ones, count_roots]
_ ≤ (∑ x in p.roots.toFinset, p.derivative.rootMultiplicity x) +
((p.derivative.roots.toFinset \ p.roots.toFinset).card + 1) :=
(add_le_add
(Finset.sum_le_sum fun x _ => rootMultiplicity_sub_one_le_derivative_rootMultiplicity _ _)
p.card_roots_toFinset_le_card_roots_derivative_diff_roots_succ)
_ ≤ (∑ x in p.roots.toFinset, p.derivative.roots.count x) +
((∑ x in p.derivative.roots.toFinset \ p.roots.toFinset,
p.derivative.roots.count x) + 1) := by
simp only [← count_roots]
refine' add_le_add_left (add_le_add_right ((Finset.card_eq_sum_ones _).trans_le _) _) _
refine' Finset.sum_le_sum fun x hx => Nat.succ_le_iff.2 <| _
rw [Multiset.count_pos, ← Multiset.mem_toFinset]
exact (Finset.mem_sdiff.1 hx).1
_ = Multiset.card (derivative p).roots + 1 := by
rw [← add_assoc, ← Finset.sum_union Finset.disjoint_sdiff, Finset.union_sdiff_self_eq_union, ←
Multiset.toFinset_sum_count_eq, ← Finset.sum_subset (Finset.subset_union_right _ _)]
intro x _ hx₂
simpa only [Multiset.mem_toFinset, Multiset.count_eq_zero] using hx₂
#align polynomial.card_roots_le_derivative Polynomial.card_roots_le_derivative

/-- The number of real roots of a polynomial is at most the number of roots of its derivative plus
one. -/
theorem card_rootSet_le_derivative {F : Type _} [CommRing F] [Algebra F ℝ] (p : F[X]) :
Fintype.card (p.rootSet ℝ) ≤ Fintype.card (p.derivative.rootSet ℝ) + 1 := by
simpa only [rootSet_def, Finset.coe_sort_coe, Fintype.card_coe, derivative_map] using
card_roots_toFinset_le_derivative (p.map (algebraMap F ℝ))
#align polynomial.card_root_set_le_derivative Polynomial.card_rootSet_le_derivative

end Polynomial

0 comments on commit 282e596

Please sign in to comment.