From 6dda5d3197b7bcaf8b03a57dee23579f96f97ac2 Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 13:59:29 +0000 Subject: [PATCH 1/6] Consolidate core onto Mathlib's Splits API and general lemmas - Rewrite about 370 calls in 125 files from local root-count, product-over-roots, zero-or-splits, derivative and divisibility helpers to `Polynomial.splits_iff_card_roots`, `Splits.eval_eq_prod_roots`, `Splits.mul`/`pow`/`derivative`, `IsRoot.dvd`, `Splits.exists_eval_eq_zero` and `Splits.of_dvd`. - Use Mathlib's `natDegree_add_eq_{left,right}_of_natDegree_lt`, dropping the leading-coefficient hypothesis. - Derive the `StrictInterl.mul_X*` special cases from the general `StrictInterl.mul_X_sub_C_both`, moved earlier in the import order. - Merge in-repository duplicates: `pairwise_le_of_listInterlaces`, `hasNonnegCoeffs_C_mul`, `Interl.toStrictInterl_of_ne`, `Splits.mem_range_of_isRoot` and the divX splitting lemma. - Derive the quadratic splitting forms from one discriminant criterion. - Add namespaced reverse/reflect shims (`Polynomial.Splits.reverse`, `.reflect`, `.of_reverse`, `splits_reverse_iff`, `splits_reflect_iff`). - Make 42 file-local helpers private. Names still used downstream keep dated deprecations. Co-Authored-By: Claude Opus 5.5 --- RealRooted/AffineDerivative.lean | 29 +++-- RealRooted/AffineFamily.lean | 14 +-- RealRooted/AffineFamily/Basic.lean | 2 +- RealRooted/AffineFamily/Boundary.lean | 28 +++-- RealRooted/AffineFamily/LowDegree.lean | 4 +- RealRooted/AffineFamily/Wronskian.lean | 8 +- RealRooted/AissenSchoenbergWhitney.lean | 4 +- .../CyclicPathDescents.lean | 2 +- RealRooted/Applications/OEIS/A080721.lean | 4 +- RealRooted/Applications/OEIS/A132885.lean | 2 +- .../Applications/OEIS/A144696/Endpoints.lean | 2 +- .../OEIS/A144696/StrictInterlacing.lean | 2 +- RealRooted/Applications/OEIS/A151775.lean | 2 +- RealRooted/Applications/OEIS/A275442.lean | 10 +- RealRooted/Applications/OEIS/A297191.lean | 8 +- RealRooted/Applications/OEIS/A304330.lean | 6 +- RealRooted/Applications/OEIS/A304334.lean | 3 +- .../Applications/OEIS/CubicParentRows.lean | 4 +- RealRooted/ArrayPolynomialDeterminant.lean | 2 +- RealRooted/ArrayPolynomialSchur.lean | 2 +- RealRooted/Basic/AffineInterlacing.lean | 4 +- RealRooted/Basic/Coefficients.lean | 8 +- RealRooted/Basic/PolynomialFacts.lean | 22 +--- RealRooted/Basic/RootLists.lean | 33 ++++- RealRooted/BernsteinCone.lean | 2 +- RealRooted/Bezoutian/StrictInterleaving.lean | 2 +- .../BinaryRunTransformation/Anchor.lean | 4 +- .../BinaryRunTransformation/Continuation.lean | 9 +- .../BinaryRunTransformation/CrossLength.lean | 4 +- .../MultiplierMotzkin.lean | 2 +- RealRooted/BrandenLeite/ChainPolynomial.lean | 6 +- .../ChowInterlacingQuotient.lean | 2 +- .../BrandenVecchi/ChowInterlacingSign.lean | 8 +- .../ChowResolutionInterlacing.lean | 4 +- .../BrandenVecchi/ChowTotallyNonneg.lean | 16 +-- .../BrandenVecchi/ReflectionInterlacing.lean | 2 +- .../Stability/Routh.lean | 11 +- .../Stability/Routh/ProperPosition.lean | 2 +- .../Stability/Routh/Reverse.lean | 2 +- .../Stability/Routh/WeakReverse.lean | 2 +- RealRooted/CoefficientShape.lean | 2 +- RealRooted/CombinatorialExamples/Motzkin.lean | 5 +- .../GammaOperator.lean | 2 +- .../PeakValues/WeightedInterleaving.lean | 2 +- .../SingletonFreeSetPartitions.lean | 2 +- .../SturmDerangementsExc.lean | 9 +- .../CombinatorialExamples/SuperEulerian.lean | 16 ++- .../PairBridge/Reduction/CommonRoot.lean | 2 +- .../RootCountCombinatorics.lean | 27 ++-- RealRooted/CommonInterleaver/RootDesc.lean | 10 +- .../CommonInterleaver/RootSelection.lean | 6 +- RealRooted/CommonInterleaver/RootSlots.lean | 17 +-- .../SameDegreeRootCount.lean | 16 +-- .../SuccDegreeLowDegree.lean | 8 +- RealRooted/CommonInterleaverExamples.lean | 4 +- RealRooted/Compatibility/Affine.lean | 4 +- RealRooted/Compatibility/Basic.lean | 2 +- .../CutTransformObstruction.lean | 4 +- RealRooted/Compatibility/LeanderOutput.lean | 2 +- RealRooted/Compatibility/Pair.lean | 2 +- RealRooted/DegreeDropDivXPrec.lean | 14 +-- RealRooted/DegreeDropReversal.lean | 63 +++------- RealRooted/Derivative/FamilyClosure.lean | 2 + RealRooted/Derivative/Interlacing.lean | 40 ++---- RealRooted/Derivative/ShiftRootMatching.lean | 4 +- RealRooted/Derivative/SimpleRoots.lean | 2 +- .../DerivativeRecurrence/EndpointWindow.lean | 14 ++- .../DerivativeRecurrence/Interlacing.lean | 5 +- .../DerivativeRecurrence/RootWindow.lean | 16 +-- .../EulerBidiagonal/ComparisonData.lean | 2 +- RealRooted/EulerBidiagonal/General.lean | 4 +- RealRooted/EulerBidiagonal/GeneralRows.lean | 2 +- RealRooted/EulerBidiagonal/Location.lean | 2 +- RealRooted/EulerBidiagonal/PairTheorem.lean | 6 +- RealRooted/EulerOperator.lean | 5 +- RealRooted/EulerOperator/Correction.lean | 4 +- RealRooted/EulerOperator/Pencil.lean | 8 +- RealRooted/EulerOperator/Polar.lean | 4 +- RealRooted/EulerOperator/Polar/Adjacent.lean | 9 +- RealRooted/EulerOperator/ScaledPolar.lean | 2 +- RealRooted/EulerianMixedCompatibility.lean | 2 +- RealRooted/Favard.lean | 2 +- RealRooted/Favard/Affine/Basic.lean | 2 +- RealRooted/FiniteFreeMultiplicative.lean | 2 +- RealRooted/FiniteFreeRootCount.lean | 8 +- RealRooted/FolkloreLemma.lean | 8 +- RealRooted/GammaPencil/Invariants.lean | 2 +- RealRooted/GammaTransform/Basic.lean | 4 +- RealRooted/GammaTransform/Preservation.lean | 8 +- RealRooted/GammaTransform/ProperPosition.lean | 2 +- RealRooted/GammaTransform/RootMap.lean | 2 +- RealRooted/GarloffWagner/Iterated.lean | 4 +- RealRooted/GarloffWagner/Theorem12.lean | 10 +- .../Narayana/JacobiTransport.lean | 9 +- .../Narayana/PFFacts.lean | 2 +- .../ShiftedDifferenceInterlacingAnalytic.lean | 4 +- .../Graph/IndependencePolynomial/Basic.lean | 2 +- RealRooted/Hadamard/Basic.lean | 7 +- RealRooted/Hadamard/Grace.lean | 8 +- RealRooted/Hadamard/Newton.lean | 4 +- RealRooted/Hadamard/SchurSzegoSimple.lean | 2 +- RealRooted/Hadamard/SchurSzegoStrict.lean | 6 +- RealRooted/Hermite/Poulain.lean | 2 +- .../HermiteBiehler/ConverseLowDegree.lean | 4 +- RealRooted/HermiteBiehler/Forward.lean | 17 +-- RealRooted/HermiteBiehler/OrientedPencil.lean | 4 +- RealRooted/HosterStump/Chow.lean | 10 +- RealRooted/HosterStump/Sequence.lean | 3 +- RealRooted/Interlacing/ConeBounds.lean | 7 +- RealRooted/Interlacing/NegativeRoots.lean | 12 +- RealRooted/Interlacing/OuterDifference.lean | 4 +- RealRooted/Interlacing/PencilPreserver.lean | 2 +- .../Interlacing/RemainderCertificate.lean | 2 +- RealRooted/Interlacing/Residue.lean | 4 +- RealRooted/Interlacing/ResidueCriterion.lean | 2 +- RealRooted/Interlacing/Reversal.lean | 14 +-- RealRooted/Interlacing/RootCountSigns.lean | 2 +- RealRooted/Interlacing/WindowInduction.lean | 7 -- RealRooted/IteratedDerivativeShift.lean | 2 +- RealRooted/Jacobi/Markoff.lean | 2 +- .../JacobiDeformation/ImageProduct.lean | 2 +- RealRooted/JacobiDeformation/Strict.lean | 2 +- RealRooted/JensenPencilContraction.lean | 4 +- .../JensenPencilPositiveContraction.lean | 4 +- RealRooted/Kurtz.lean | 4 +- RealRooted/Linear.lean | 87 ++++++------- RealRooted/LinearPowerFamily.lean | 5 +- .../LiuOppositeSigns/PositiveSplitPair.lean | 2 +- .../PositiveSplitRootCount.lean | 9 +- RealRooted/LiuOppositeSigns/RootCount.lean | 6 +- .../LiuOppositeSigns/RootCountClosure.lean | 8 +- .../XSub/IntervalRootCount/GapCounts.lean | 10 +- .../XSub/IntervalRootCount/LeftSuccessor.lean | 2 +- .../IntervalRootCount/RightSuccessor.lean | 2 +- .../XSub/IntervalRootCount/SameDegree.lean | 2 +- .../XSub/IntervalRootCount/UpperTail.lean | 8 +- RealRooted/MaWang/CountBounds.lean | 20 +-- RealRooted/MaWang/StrictSigns/Assembly.lean | 22 ++-- RealRooted/MaWang/StrictSigns/RootSigns.lean | 14 +-- RealRooted/MaWang/Strong.lean | 6 +- RealRooted/MaWang/Weak/Regularization.lean | 21 +--- RealRooted/MaWang/Weak/Successor.lean | 4 +- .../Mathlib/Algebra/Polynomial/Reverse.lean | 70 +++++++++++ RealRooted/MatrixInterlacing/AffinePair.lean | 4 +- RealRooted/MultiplierSequence/Infinite.lean | 7 +- .../MultiplierSequence/InvPochhammer.lean | 2 +- .../PolyaSchur/LaguerrePolya/Derivative.lean | 2 +- .../MultiplierSequence/PolyaSchur/Schur.lean | 2 +- .../MultiplierSequence/ProperPosition.lean | 4 +- RealRooted/NarayanaTransformation/Basis.lean | 11 +- RealRooted/ObreschkoffContinuity.lean | 9 +- RealRooted/ObreschkoffConverse/Converse.lean | 7 +- RealRooted/ObreschkoffConverse/DegreeGap.lean | 2 +- .../ObreschkoffConverse/Derivative.lean | 4 +- RealRooted/ObreschkoffConverse/Forward.lean | 6 +- .../ObreschkoffConverse/Regularization.lean | 20 +-- RealRooted/OperatorInterlacingUpgrade.lean | 10 +- .../OperatorInterlacingUpgrade/RootOrder.lean | 4 +- RealRooted/OperatorMatrix/Directed.lean | 3 +- RealRooted/OperatorMatrix/MixedLemma.lean | 8 +- RealRooted/OrderedRoots.lean | 10 +- RealRooted/PFPolynomial.lean | 34 +++--- .../Descents/WeakLeftPeakOrderedCut.lean | 2 +- .../ExceptionalOffset/NodeInterlacing.lean | 11 +- .../ExceptionalOffset/PencilSplitting.lean | 2 +- .../ProperPositionAndParameters.lean | 8 +- .../ToricContribution/FiniteOffsets.lean | 2 +- .../ToricContribution/IntervalInsertion.lean | 10 +- RealRooted/PolarDerivative.lean | 8 +- RealRooted/PosCombo.lean | 8 +- RealRooted/PosCombo/Degree.lean | 5 +- RealRooted/ProductFamily.lean | 4 +- RealRooted/ProductOrientation.lean | 8 +- RealRooted/QuadraticInterlacingClosure.lean | 28 ++--- RealRooted/QuadraticRoot.lean | 22 +--- .../ReciprocalShift/ProperPosition.lean | 4 +- .../ReflectedRootCountLocalConstancy.lean | 2 +- RealRooted/RootContinuity.lean | 30 ++--- RealRooted/RootCountFinite.lean | 2 +- RealRooted/RootCounting/SignChanges.lean | 2 +- RealRooted/RootVieta/Newton.lean | 2 +- RealRooted/SameDegreeCubicRootCount.lean | 4 +- RealRooted/SameDegreeDerivative.lean | 6 +- .../SamePhaseStability/Nonnegative.lean | 2 +- RealRooted/SequenceClosure.lean | 22 ++-- RealRooted/ShiftLemma.lean | 6 +- RealRooted/SortedRoots/Exhibited.lean | 2 +- RealRooted/SuccDegreeLeftEndpoint.lean | 10 +- .../SymmetricDecomposition/Decomposition.lean | 13 +- .../EulerianTransform.lean | 4 +- .../SymmetricDecomposition/FPolynomial.lean | 20 +-- .../FPolynomialInterlacing.lean | 2 +- .../FPolynomialSequence.lean | 10 +- .../SymmetricDecomposition/Theorem26.lean | 24 ++-- .../Examples/RowParityFactorization.lean | 4 +- RealRooted/Tactic/Finish.lean | 56 +++++---- RealRooted/Tactic/SideGoals.lean | 6 +- RealRooted/Tactic/SignAssembly.lean | 6 +- RealRooted/Tactic/WagnerX/Frontend.lean | 12 +- RealRooted/Tactic/WagnerX/PositiveLag.lean | 4 +- .../ThreeTermRecurrence/LagFeedback.lean | 8 +- .../Transforms/BrandenE/WeightedSum.lean | 4 +- RealRooted/VeroneseMatrix.lean | 6 +- RealRooted/WagnerRightSum.lean | 33 ++--- RealRooted/WagnerRightSum/Sign.lean | 18 ++- RealRooted/WagnerX/AffineFactors.lean | 99 +-------------- RealRooted/WagnerX/ListInterlacing.lean | 115 +++++++++++++----- RealRooted/WagnerX/NonnegativeRoots.lean | 84 ++++++------- RealRooted/WagnerX/ProperPosition.lean | 6 +- RealRooted/WeightedSum.lean | 2 +- RealRooted/Wronskian/Algebra.lean | 8 +- RealRooted/Wronskian/Forward.lean | 4 +- RealRooted/Wronskian/Successor/Splits.lean | 2 +- 213 files changed, 999 insertions(+), 1059 deletions(-) diff --git a/RealRooted/AffineDerivative.lean b/RealRooted/AffineDerivative.lean index 580820954..e16ce1397 100644 --- a/RealRooted/AffineDerivative.lean +++ b/RealRooted/AffineDerivative.lean @@ -682,7 +682,7 @@ lemma roots_card_of_sub_pred {p : ℝ[X]} (hp : p ≠ 0) have h1 : p.roots.card ≤ p.natDegree := card_roots' p have h2 : S.card ≤ p.roots.card := Multiset.card_le_card hle have hne_card : p.roots.card ≠ p.natDegree := - fun h => hne (splits_of_card_roots h) + fun h => hne (Polynomial.splits_iff_card_roots.mpr h) -- p.roots.card = natDegree - 1 have hrc : p.roots.card = p.natDegree - 1 := by lia -- Factor p = rprod * q where rprod = ∏(X - C r) for r ∈ p.roots @@ -708,7 +708,7 @@ lemma roots_card_of_sub_pred {p : ℝ[X]} (hp : p ≠ 0) rw [natDegree_multiset_prod_X_sub_C_eq_card, hrc, ← hpq] at h3 lia have hq_split := (isRealRooted_of_degree_one hq_deg).2 - have hq_card := card_roots_of_splits hq_split + have hq_card := Polynomial.splits_iff_card_roots.mp hq_split rw [hq_empty, Multiset.card_zero, hq_deg] at hq_card lia @@ -754,7 +754,7 @@ private lemma strictInterl_of_extra_root_left {f g : ℝ[X]} (hf₀ : f ≠ 0) ( (hu : u ≤ r₁) : StrictInterl g f := by have hss_sorted : ss.Pairwise (· ≤ ·) := - sorted_of_listInterlaces ss (r₁ :: rest) hrs_sorted hint + pairwise_le_of_listInterlaces ss (r₁ :: rest) hint have hu_le_all : ∀ s ∈ ss, u ≤ s := fun s hs => le_trans hu (listInterlaces_all_ge ss rest r₁ hint s hs) have hug_sorted : (u :: ss).Pairwise (· ≤ ·) := by simp_all @@ -781,7 +781,8 @@ theorem strictInterl_affine_derivative {f : ℝ[X]} (hf : f.Splits) set rs := f.roots.sort (· ≤ ·) with hrs_def have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hrs_eq : (↑rs : Multiset ℝ) = f.roots := Multiset.sort_eq .. - have hrs_length : rs.length = d := by rw [hrs_def, Multiset.length_sort, card_roots_of_splits hf] + have hrs_length : rs.length = d := by + rw [hrs_def, Multiset.length_sort, Polynomial.splits_iff_card_roots.mp hf] have hrs_root : ∀ r ∈ rs, f.IsRoot r := by simp_all have hsub_rs : (↑rs : Multiset ℝ) ≤ f.roots := le_of_eq hrs_eq have hgap_rs : ConsecNoRoots f rs := consecNoRoots_of_sorted_eq hrs_eq hrs_sorted @@ -812,7 +813,7 @@ theorem strictInterl_affine_derivative {f : ℝ[X]} (hf : f.Splits) roots_card_of_sub_pred hg₀.ne_zero hss_sub (by rw [Multiset.coe_card, hss_length, hg_deg]; lia) have hss_eq_card : (↑ss : Multiset ℝ).card + 1 = g.roots.card := by - rw [Multiset.coe_card, hss_length, card_roots_of_splits hg_rr, hg_deg] + rw [Multiset.coe_card, hss_length, Polynomial.splits_iff_card_roots.mp hg_rr, hg_deg] lia obtain ⟨r₁, rest, hrs_cons⟩ : ∃ r₁ rest, rs = r₁ :: rest := by cases h : rs with @@ -937,7 +938,7 @@ theorem strictInterl_affine_derivative {f : ℝ[X]} (hf : f.Splits) calc m = f.roots.count r₁ := by lia _ ≤ f.roots.card := Multiset.count_le_card _ _ - _ = d := by rw [card_roots_of_splits hf, hd_def] + _ = d := by rw [Polynomial.splits_iff_card_roots.mp hf, hd_def] have hq_deg : q.natDegree = d - m := by have hdegmul := natDegree_mul (p := (X - C r₁) ^ m) (q := q) @@ -953,11 +954,11 @@ theorem strictInterl_affine_derivative {f : ℝ[X]} (hf : f.Splits) lia have hcard_step : qg.roots.card = q.roots.card + 1 := by calc - qg.roots.card = qg.natDegree := card_roots_of_splits hqg_rr.2 + qg.roots.card = qg.natDegree := Polynomial.splits_iff_card_roots.mp hqg_rr.2 _ = d - (m - 1) := hqg_deg _ = d - m + 1 := by lia _ = q.natDegree + 1 := by lia - _ = q.roots.card + 1 := by rw [← card_roots_of_splits hq_rr.2] + _ = q.roots.card + 1 := by rw [← Polynomial.splits_iff_card_roots.mp hq_rr.2] have hPg_nonneg' : 0 ≤ -(((-1 : ℝ) ^ q.roots.card) * Pg) := by rw [hcard_step, pow_add, pow_one, mul_neg_one] at hPg_nonneg grind @@ -970,8 +971,8 @@ theorem strictInterl_affine_derivative {f : ℝ[X]} (hf : f.Splits) have hmulp' : 0 ≤ -(Pg * Pq) := by nlinarith [hmulp, hsquare] linarith have hEval_nonpos : qg.eval r₁ * q.eval r₁ ≤ 0 := by - rw [eval_eq_leadingCoeff_mul_prod_sub hqg_rr.2 r₁, - eval_eq_leadingCoeff_mul_prod_sub hq_rr.2 r₁, + rw [Polynomial.Splits.eval_eq_prod_roots hqg_rr.2 r₁, + Polynomial.Splits.eval_eq_prod_roots hq_rr.2 r₁, show (q.roots.map (r₁ - ·)).prod = Pq by lia, show (qg.roots.map (r₁ - ·)).prod = Pg by lia] have hlc_pos : 0 < qg.leadingCoeff * q.leadingCoeff := @@ -1008,9 +1009,11 @@ theorem strictInterl_affine_derivative_deg_one {f : ℝ[X]} (hf : f.Splits) exact mul_pos (by simp_all) hf₀ -- f and g each have exactly one root obtain ⟨r, hr_eq⟩ := - Multiset.card_eq_one.mp (show f.roots.card = 1 by rw [card_roots_of_splits hf, hdeg]) + Multiset.card_eq_one.mp (show f.roots.card = 1 by + rw [Polynomial.splits_iff_card_roots.mp hf, hdeg]) obtain ⟨s, hs_eq⟩ := - Multiset.card_eq_one.mp (show g.roots.card = 1 by rw [card_roots_of_splits hg_rr.2, hg_deg]) + Multiset.card_eq_one.mp (show g.roots.card = 1 by + rw [Polynomial.splits_iff_card_roots.mp hg_rr.2, hg_deg]) have hr_root : f.IsRoot r := (mem_roots hf₀.ne_zero).mp (hr_eq ▸ Multiset.mem_singleton_self r) have hr_nonpos : r ≤ 0 := hroots_nonpos r (hr_eq ▸ Multiset.mem_singleton_self r) @@ -1026,7 +1029,7 @@ theorem strictInterl_affine_derivative_deg_one {f : ℝ[X]} (hf : f.Splits) exact hf₀ -- g(r) = lc(g) * (r - s) have hgr_eq : g.eval r = g.leadingCoeff * (r - s) := by - rw [eval_eq_leadingCoeff_mul_prod_sub hg_rr.2 r, hs_eq]; simp + rw [Polynomial.Splits.eval_eq_prod_roots hg_rr.2 r, hs_eq]; simp -- s ≤ r have hsr : s ≤ r := by have : 0 < r - s := by simp_all diff --git a/RealRooted/AffineFamily.lean b/RealRooted/AffineFamily.lean index fb9a03901..9d945f321 100644 --- a/RealRooted/AffineFamily.lean +++ b/RealRooted/AffineFamily.lean @@ -111,8 +111,7 @@ private lemma natDegree_shifted_pair_eq_succ_of_affine_family rcases lt_or_eq_of_le hdeg_right with hlt | heq · have hg_lt : g.natDegree < (X * f).natDegree := by simp_all have hsum_deg : (g + X * f).natDegree = (X * f).natDegree := - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - hg_lt hXf_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hg_lt simp_all · have hg_eq : g.natDegree = (X * f).natDegree := by simp_all have hsum_deg : (g + X * f).natDegree = (X * f).natDegree := @@ -143,8 +142,7 @@ private lemma strictInterl_of_strictInterl_shifted_pair_sameDegree (hfnn.pos_leadingCoeff hf0).X_mul have hg_lt : g.natDegree < (X * f).natDegree := by lia have hsum_deg : (g + X * f).natDegree = (X * f).natDegree := - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - hg_lt hXf_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hg_lt lia let a : ℝ := f.leadingCoeff⁻¹ have ha_ne : a ≠ 0 := inv_ne_zero (ne_of_gt hf_pos) @@ -717,12 +715,14 @@ lemma isRealRooted_affine_factor {s t : ℝ} (hs : 0 < s) : lemma affine_family_of_zero_left {g : ℝ[X]} (hg_ne : g ≠ 0) (hg_splits : g.Splits) : ∀ {s t : ℝ}, 0 < s → 0 < t → - ((((C s * X + C t) * (0 : ℝ[X])) + g) ≠ 0 ∧ (((C s * X + C t) * (0 : ℝ[X])) + g).Splits) := by + ((((C s * X + C t) * (0 : ℝ[X])) + g) ≠ 0 ∧ + (((C s * X + C t) * (0 : ℝ[X])) + g).Splits) := by simp [*] lemma affine_family_of_zero_right {f : ℝ[X]} (hf_ne : f ≠ 0) (hf_splits : f.Splits) : ∀ {s t : ℝ}, 0 < s → 0 < t → - ((((C s * X + C t) * f) + (0 : ℝ[X])) ≠ 0 ∧ (((C s * X + C t) * f) + (0 : ℝ[X])).Splits) := by + ((((C s * X + C t) * f) + (0 : ℝ[X])) ≠ 0 ∧ + (((C s * X + C t) * f) + (0 : ℝ[X])).Splits) := by intro s t hs ht simpa using isRealRooted_mul (isRealRooted_affine_factor (t := t) hs).1 (isRealRooted_affine_factor (t := t) hs).2 hf_ne hf_splits @@ -730,7 +730,7 @@ lemma affine_family_of_zero_right {f : ℝ[X]} (hf_ne : f ≠ 0) (hf_splits : f. lemma hasNonnegCoeffs_affine_linear {a b : ℝ} (ha : 0 ≤ a) (hb : 0 ≤ b) : HasNonnegCoeffs (C a * X + C b) := by have hCb : HasNonnegCoeffs (C b) := by rintro (_ | n) <;> simp [hb] - exact (nonnegCoeffs_C_mul ha hasNonnegCoeffs_X).add hCb + exact (hasNonnegCoeffs_C_mul ha hasNonnegCoeffs_X).add hCb lemma interl_one_affine_linear {a b : ℝ} (ha : 0 < a) : Interl (1 : ℝ[X]) (C a * X + C b) := by diff --git a/RealRooted/AffineFamily/Basic.lean b/RealRooted/AffineFamily/Basic.lean index 178310eb1..014690c1e 100644 --- a/RealRooted/AffineFamily/Basic.lean +++ b/RealRooted/AffineFamily/Basic.lean @@ -91,7 +91,7 @@ theorem isRealRooted_affine_combo_of_strictInterl_nonneg {f g : ℝ[X]} StrictInterl.add_of_right_of_posLeadingCoeff hg_Xf hsXf hg_pos hsXf_pos have hmid_nonneg : HasNonnegCoeffs (g + C s * (X * f)) := by refine hgnn.add ?_ - exact (nonnegCoeffs_C_mul hs.le hfnn.X_mul) + exact (hasNonnegCoeffs_C_mul hs.le hfnn.X_mul) have hmid_pos : HasPosLeadingCoeff (g + C s * (X * f)) := hmid_nonneg.pos_leadingCoeff hmid.1.1 have hsum : StrictInterl (C t * f + (g + C s * (X * f))) (X * f) := diff --git a/RealRooted/AffineFamily/Boundary.lean b/RealRooted/AffineFamily/Boundary.lean index eefc9fd3b..6606d9a2a 100644 --- a/RealRooted/AffineFamily/Boundary.lean +++ b/RealRooted/AffineFamily/Boundary.lean @@ -42,7 +42,7 @@ private lemma affine_family_pair_data {f g : ℝ[X]} X * f ≠ 0 ∧ HasPosLeadingCoeff (C t * f + g) ∧ HasPosLeadingCoeff (X * f) := by - have hCt_nonneg : HasNonnegCoeffs (C t * f) := nonnegCoeffs_C_mul ht.le hfnn + have hCt_nonneg : HasNonnegCoeffs (C t * f) := hasNonnegCoeffs_C_mul ht.le hfnn have hsum_nonneg : HasNonnegCoeffs (C t * f + g) := hCt_nonneg.add hgnn have hXf_nonneg : HasNonnegCoeffs (X * f) := hfnn.X_mul have hCt_ne : C t * f ≠ 0 := @@ -162,7 +162,7 @@ protected theorem AffineFamily.isRealRooted_of_add_C_mul_right_family_of_natDegr have hμf_deg_lt : (C μ * f₀).natDegree < g₀.natDegree := by simpa [natDegree_C_mul hμ_pos.ne'] using hdeg₀ have hsum_deg : (g₀ + C μ * f₀).natDegree = g₀.natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hμf_deg_lt hg₀_pos + Polynomial.natDegree_add_eq_left_of_natDegree_lt hμf_deg_lt have hsum_monic : (g₀ + C μ * f₀).Monic := by unfold Polynomial.Monic Polynomial.leadingCoeff rw [hsum_deg, coeff_add, coeff_eq_zero_of_natDegree_lt hμf_deg_lt, @@ -172,9 +172,13 @@ protected theorem AffineFamily.isRealRooted_of_add_C_mul_right_family_of_natDegr (f := g₀) (g := g₀ + C μ * f₀) (z := z) (ε := ε) hε_pos hz_aeval hg₀_monic hsum_monic hsum_deg hcoeff (hfamily₀ hμ_pos).2 - have hw_im_zero : w.im = 0 := - RealRooted.im_eq_zero_of_mem_aroots_of_isRealRooted - (hfamily₀ hμ_pos).1 (hfamily₀ hμ_pos).2 hw_root + have hsum_rr := hfamily₀ hμ_pos + have hw_isRoot : + ((g₀ + C μ * f₀).map (algebraMap ℝ ℂ)).IsRoot w := by + simp_all + have hw_im_zero : w.im = 0 := by + rcases hsum_rr.2.mem_range_of_isRoot hsum_rr.1 hw_isRoot with ⟨r, rfl⟩ + simp have hbound_eq : ((g₀.natDegree + 1) * ε) ^ ((g₀.natDegree : ℝ)⁻¹) * R = δ / 2 := by have hmul : @@ -281,9 +285,7 @@ protected lemma AffineFamily.isRealRooted_add_left_of_affine_family_of_natDegree have hsum_deg : (C t * f + g).natDegree = g.natDegree := by have hCt_deg : (C t * f).natDegree = f.natDegree := by rw [natDegree_C_mul ht.ne'] exact - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - (by lia) - (hgnn.pos_leadingCoeff hg0) + Polynomial.natDegree_add_eq_right_of_natDegree_lt (by lia) apply AffineFamily.isRealRooted_of_add_C_mul_right_family_of_natDegree_le · intro s hs simpa [add_assoc, add_left_comm, add_comm, mul_assoc, left_distrib, right_distrib] using @@ -346,7 +348,7 @@ private lemma isRealRooted_add_X_mul_right_of_affine_family have hXf_nonneg : HasNonnegCoeffs (X * f) := hfnn.X_mul have hXf_ne : X * f ≠ 0 := mul_ne_zero X_ne_zero hf0 have hCsXf_nonneg : HasNonnegCoeffs (C s * (X * f)) := - nonnegCoeffs_C_mul hs.le hXf_nonneg + hasNonnegCoeffs_C_mul hs.le hXf_nonneg have hCsXf_ne : C s * (X * f) ≠ 0 := mul_ne_zero (C_ne_zero.mpr hs.ne') hXf_ne have hbase_nonneg : HasNonnegCoeffs (g + C s * (X * f)) := @@ -370,8 +372,8 @@ private lemma isRealRooted_add_X_mul_right_of_affine_family have hbase_deg : f.natDegree ≤ (g + C s * (X * f)).natDegree := by rcases lt_trichotomy g.natDegree (X * f).natDegree with hdeg | hdeg | hdeg · have hsum_deg : (g + C s * (X * f)).natDegree = (C s * (X * f)).natDegree := - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - (by simpa [natDegree_C_mul hs.ne'] using hdeg) hCsXf_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt + (by simpa [natDegree_C_mul hs.ne'] using hdeg) rw [hsum_deg, natDegree_C_mul hs.ne', natDegree_mul X_ne_zero hf0, natDegree_X] lia · have hsum_deg : (g + C s * (X * f)).natDegree = g.natDegree := @@ -379,8 +381,8 @@ private lemma isRealRooted_add_X_mul_right_of_affine_family (by simpa [natDegree_C_mul hs.ne'] using hdeg) hg_pos hCsXf_pos simp_all · have hsum_deg : (g + C s * (X * f)).natDegree = g.natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff - (by simpa [natDegree_C_mul hs.ne'] using hdeg) hg_pos + Polynomial.natDegree_add_eq_left_of_natDegree_lt + (by simpa [natDegree_C_mul hs.ne'] using hdeg) rw [hsum_deg] have hXf_deg : (X * f).natDegree = f.natDegree + 1 := by simp_all lia diff --git a/RealRooted/AffineFamily/LowDegree.lean b/RealRooted/AffineFamily/LowDegree.lean index 36ccdc42f..dd3e30e82 100644 --- a/RealRooted/AffineFamily/LowDegree.lean +++ b/RealRooted/AffineFamily/LowDegree.lean @@ -63,7 +63,7 @@ private theorem not_degree_gap_ge_two_of_add_left_family_nonneg intro μ hμ have hbase := hfamily hμ have hbase_deg : (C μ * f + g).natDegree = g.natDegree := by - apply natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff _ hg_pos + apply Polynomial.natDegree_add_eq_right_of_natDegree_lt rw [natDegree_C_mul hμ.ne'] lia have hn_lt : n < (C μ * f + g).natDegree := by lia @@ -295,7 +295,7 @@ private lemma eval_nonpos_at_root_of_degree_one_of_affine_family nlinarith [sq_nonneg (2 * (s * a + A) * x + (a + B))] have hq_deg2 : q.natDegree = 2 := by rw [hq_eq]; exact natDegree_quadratic hquad_pos.ne' obtain ⟨x, hx_mem⟩ := Multiset.card_pos_iff_exists_mem.mp (show 0 < q.roots.card by - rw [card_roots_of_splits hq_rr.2, hq_deg2] + rw [Polynomial.splits_iff_card_roots.mp hq_rr.2, hq_deg2] lia) exact hq_noRoot x ((mem_roots hq_rr.1).mp hx_mem) diff --git a/RealRooted/AffineFamily/Wronskian.lean b/RealRooted/AffineFamily/Wronskian.lean index 4d2b3396f..c9c289566 100644 --- a/RealRooted/AffineFamily/Wronskian.lean +++ b/RealRooted/AffineFamily/Wronskian.lean @@ -420,11 +420,11 @@ private lemma allComboRealRooted_of_affine_family_succDegree_not_isRoot_zero simp_all have hrs_len : rs.length = g.natDegree := by rw [show rs = g.roots.sort (· ≤ ·) by lia, Multiset.length_sort, - card_roots_of_splits hg_rr.2] + Polynomial.splits_iff_card_roots.mp hg_rr.2] have hus_eq : (↑us : Multiset ℝ) = f.roots := by apply Multiset.eq_of_le_of_card_le hus_sub calc - f.roots.card = f.natDegree := card_roots_of_splits hf_rr.2 + f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf_rr.2 _ = g.natDegree - 1 := by lia _ = rs.length - 1 := by lia _ = us.length := hus_len.symm @@ -458,8 +458,8 @@ protected lemma AffineFamily.allComboRealRooted_of_affine_family_succDegree have hdeg_lt : f.natDegree < g.natDegree := by lia calc (g + f).natDegree = g.natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff - hdeg_lt (hgnn.pos_leadingCoeff hg0) + Polynomial.natDegree_add_eq_left_of_natDegree_lt + hdeg_lt _ = f.natDegree + 1 := hsucc have hshift_aff : ∀ {s t : ℝ}, 0 < s → 0 < t → diff --git a/RealRooted/AissenSchoenbergWhitney.lean b/RealRooted/AissenSchoenbergWhitney.lean index 21c6751cf..6a09253ad 100644 --- a/RealRooted/AissenSchoenbergWhitney.lean +++ b/RealRooted/AissenSchoenbergWhitney.lean @@ -581,7 +581,7 @@ theorem aissenSchoenbergWhitney_reverse {p : ℝ[X]} · convert isPolyaFreqSeq_zero exact coeff_zero _ · have hp_eq : p = C p.leadingCoeff * (p.roots.map fun r ↦ X - C r).prod := - (C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hsplits)).symm + (C_leadingCoeff_mul_prod_multiset_X_sub_C (Polynomial.splits_iff_card_roots.mp hsplits)).symm rw [hp_eq] have hlc_nonneg : 0 ≤ p.leadingCoeff := (hpnn.pos_leadingCoeff hp0).le exact IsPolyaFreqSeq.const_mul p.leadingCoeff hlc_nonneg @@ -599,7 +599,7 @@ theorem IsPolyaFreqSeq.of_forall_pos_add_C_mul_splits {p q : ℝ[X]} (a := p.coeff) (b := q.coeff) (by intro μ hμ have hnn : HasNonnegCoeffs (p + C μ * q) := - hpnn.add (nonnegCoeffs_C_mul hμ.le hqnn) + hpnn.add (hasNonnegCoeffs_C_mul hμ.le hqnn) convert aissenSchoenbergWhitney_reverse hnn (hfamily hμ) (roots_nonpos_of_hasNonnegCoeffs hnn) using 1 funext n diff --git a/RealRooted/Applications/EulerianVariations/CyclicPathDescents.lean b/RealRooted/Applications/EulerianVariations/CyclicPathDescents.lean index 4bf13f747..caa908bf7 100644 --- a/RealRooted/Applications/EulerianVariations/CyclicPathDescents.lean +++ b/RealRooted/Applications/EulerianVariations/CyclicPathDescents.lean @@ -160,7 +160,7 @@ theorem cyclicPathDescentPolynomial_simple_root_description exact hsimple.roots_nodup.notMem_erase hr exact lt_of_le_of_ne (hpf.roots_nonpos r hrRoot) hrne · rw [Multiset.card_erase_of_mem hzeroMem, - card_roots_of_splits hsplits, + Polynomial.splits_iff_card_roots.mp hsplits, natDegree_cyclicPathDescentPolynomial n hn] rfl diff --git a/RealRooted/Applications/OEIS/A080721.lean b/RealRooted/Applications/OEIS/A080721.lean index 29f0fda5a..a488ea3f0 100644 --- a/RealRooted/Applications/OEIS/A080721.lean +++ b/RealRooted/Applications/OEIS/A080721.lean @@ -166,8 +166,8 @@ theorem legendre_strictInterl_polynomial (n : ℕ) : hasPosLeadingCoeff_add_of_natDegree_lt_left (by grind) haf_pos have hsum_deg : (a * legendre (n + 1) + b * legendre n).natDegree = n + 2 := - (natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff - (by grind) haf_pos).trans hdeg_af + (Polynomial.natDegree_add_eq_left_of_natDegree_lt + (by grind)).trans hdeg_af have hb_nonpos : ∀ r : ℝ, (legendre (n + 1)).IsRoot r → b.eval r ≤ 0 := by intro r _ diff --git a/RealRooted/Applications/OEIS/A132885.lean b/RealRooted/Applications/OEIS/A132885.lean index f53652a47..9ce475fb6 100644 --- a/RealRooted/Applications/OEIS/A132885.lean +++ b/RealRooted/Applications/OEIS/A132885.lean @@ -148,7 +148,7 @@ multiplicity. They are distinct and strictly negative by `splits_simple_roots_neg`. -/ theorem roots_card {n : ℕ} (hn : 2 ≤ n) : (polynomial n).roots.card = n / 2 := by - rw [card_roots_of_splits (splits_simple_roots_neg hn).1, + rw [Polynomial.splits_iff_card_roots.mp (splits_simple_roots_neg hn).1, natDegree_polynomial] end RealRooted.Applications.OEIS.A132885 diff --git a/RealRooted/Applications/OEIS/A144696/Endpoints.lean b/RealRooted/Applications/OEIS/A144696/Endpoints.lean index 11df3d3ff..03cabadf5 100644 --- a/RealRooted/Applications/OEIS/A144696/Endpoints.lean +++ b/RealRooted/Applications/OEIS/A144696/Endpoints.lean @@ -131,7 +131,7 @@ private theorem a144696Polynomial_reciprocal_strictInterl_of_two_le loweringEulerStep_nonneg hEnn (generalizedEulerian_natDegree 1 n).le have hAnn : HasNonnegCoeffs (C 2 * E) := - nonnegCoeffs_C_mul (by norm_num) hEnn + hasNonnegCoeffs_C_mul (by norm_num) hEnn have hpdeg : (C 2 * a144696Polynomial n).natDegree ≤ n := by rw [natDegree_C_mul (by norm_num), natDegree_a144696Polynomial] have hendpoint : diff --git a/RealRooted/Applications/OEIS/A144696/StrictInterlacing.lean b/RealRooted/Applications/OEIS/A144696/StrictInterlacing.lean index c344d1cfb..6232bff29 100644 --- a/RealRooted/Applications/OEIS/A144696/StrictInterlacing.lean +++ b/RealRooted/Applications/OEIS/A144696/StrictInterlacing.lean @@ -197,7 +197,7 @@ theorem a144696Auxiliary_diagonal_interlaces simp have hroots_ne : f.roots ≠ 0 := by intro hzero - have hcard : f.roots.card = f.natDegree := card_roots_of_splits hsplitsF + have hcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hsplitsF rw [hzero] at hcard simp [hfdeg] at hcard lia diff --git a/RealRooted/Applications/OEIS/A151775.lean b/RealRooted/Applications/OEIS/A151775.lean index 1a3cf7b4c..ea4eb2643 100644 --- a/RealRooted/Applications/OEIS/A151775.lean +++ b/RealRooted/Applications/OEIS/A151775.lean @@ -83,7 +83,7 @@ private theorem splits_splitFactorDerivative {a f : ℝ[X]} · exact absurd (pow_eq_zero_iff'.mp h).1 hf0 · rw [h]; exact Splits.zero have hderivative : (derivative (a * f ^ m)).Splits := - (eq_zero_or_splits_derivative (Or.inr (ha.mul (hf.pow m)))).resolve_left hD + (ha.mul (hf.pow m)).derivative exact Splits.of_dvd hderivative hD ⟨_, by rw [key, mul_comm]⟩ private theorem splits_lowerStep {f : ℝ[X]} (hf : f.Splits) : diff --git a/RealRooted/Applications/OEIS/A275442.lean b/RealRooted/Applications/OEIS/A275442.lean index 07d5d6d83..b528168b5 100644 --- a/RealRooted/Applications/OEIS/A275442.lean +++ b/RealRooted/Applications/OEIS/A275442.lean @@ -227,13 +227,13 @@ lemma strictInterl_shiftedRow_partial_step · apply strictInterl_shiftedRow_succ n · exact h13 · exact h12 - · exact h01.insert_X_lag_of_nonneg + · exact strictInterl_mul_X_of_strictInterl_of_nonneg h01 (shiftedRow_hasNonnegCoeffs n) (shiftedRow_hasNonnegCoeffs (n + 1)) · apply strictInterl_shiftedRow_succ n · exact h23 · exact StrictInterl.refl (shiftedRow_hasPosLeadingCoeff (n + 2)).ne_zero h23.1.2 - · exact h02.insert_X_lag_of_nonneg + · exact strictInterl_mul_X_of_strictInterl_of_nonneg h02 (shiftedRow_hasNonnegCoeffs n) (shiftedRow_hasNonnegCoeffs (n + 2)) /-- The bridge has the degree of the next shifted row. -/ @@ -246,15 +246,13 @@ lemma natDegree_shiftedBridge (n : ℕ) : natDegree_shiftedRow] rcases lt_trichotomy (shiftedRow (n + 2)).natDegree (X * shiftedRow n).natDegree with hlt | heq | hgt - · rw [natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hlt - (shiftedRow_hasPosLeadingCoeff n).X_mul, hright] + · rw [Polynomial.natDegree_add_eq_right_of_natDegree_lt hlt, hright] lia · rw [natDegree_add_eq_of_same_natDegree_of_posLeadingCoeff heq (shiftedRow_hasPosLeadingCoeff (n + 2)) (shiftedRow_hasPosLeadingCoeff n).X_mul, hleft] lia - · rw [natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hgt - (shiftedRow_hasPosLeadingCoeff (n + 2)), hleft] + · rw [Polynomial.natDegree_add_eq_left_of_natDegree_lt hgt, hleft] lia /-- The two positive bridge summands give it positive leading coefficient. -/ diff --git a/RealRooted/Applications/OEIS/A297191.lean b/RealRooted/Applications/OEIS/A297191.lean index 35c57809a..94925ebb4 100644 --- a/RealRooted/Applications/OEIS/A297191.lean +++ b/RealRooted/Applications/OEIS/A297191.lean @@ -356,7 +356,7 @@ end section open Real -private lemma splits_of_card_roots_finset (p : ℝ[X]) (hp : p ≠ 0) (S : Finset ℝ) +private lemma Polynomial.splits_iff_card_roots.mpr_finset (p : ℝ[X]) (hp : p ≠ 0) (S : Finset ℝ) (hS : ∀ r ∈ S, p.IsRoot r) (hcard : p.natDegree ≤ S.card) : p.Splits := by rw [splits_iff_card_roots] have h1 : S.card ≤ p.roots.card := by @@ -461,7 +461,7 @@ private lemma isRoot_polynomial_ang (n k : ℕ) (hk : k < 2 * n) : `R_{n+2} = (u+4) R_{n+1} - R_n`, a Chebyshev-type recurrence in `w = (u+4)/2`: `R_n = U_n(w) - U_{n-1}(w)`. Roots: `X + 1/X = 2 cos θ - 4` with `θ = (2k+1)π/(2n+1)`.) -/ theorem splits_polynomial (n : ℕ) : (polynomial n).Splits := by - refine splits_of_card_roots_finset _ (monic_natDegree_polynomial n).1.ne_zero + refine Polynomial.splits_iff_card_roots.mpr_finset _ (monic_natDegree_polynomial n).1.ne_zero ((Finset.range (2 * n)).image (fun k => xpar (ang n k))) ?_ ?_ · intro r hr obtain ⟨k, hk, rfl⟩ := Finset.mem_image.1 hr @@ -675,7 +675,7 @@ private lemma pencil_normalized_splits (n : ℕ) (a : ℝ) : rw [Finset.disjoint_left] intro r h1 h2 linarith [(hSL r h1).2.2, (hSR r h2).2.1] - refine splits_of_card_roots_finset G hG0 (SL ∪ SR) ?_ ?_ + refine Polynomial.splits_iff_card_roots.mpr_finset G hG0 (SL ∪ SR) ?_ ?_ · intro r hr rcases Finset.mem_union.1 hr with h | h · exact (hSL r h).1 @@ -773,7 +773,7 @@ theorem hasSimpleRoots_polynomial (n : ℕ) : HasSimpleRoots (polynomial n) := b /-- Row `n` has exactly `2n` roots, counted with multiplicity. -/ theorem roots_card_polynomial (n : ℕ) : (polynomial n).roots.card = 2 * n := by - rw [card_roots_of_splits (splits_polynomial n), natDegree_polynomial] + rw [Polynomial.splits_iff_card_roots.mp (splits_polynomial n), natDegree_polynomial] /-- The A054142 gamma polynomial whose transform is the A297191 row. -/ diff --git a/RealRooted/Applications/OEIS/A304330.lean b/RealRooted/Applications/OEIS/A304330.lean index 13a2bf5e3..3b150055a 100644 --- a/RealRooted/Applications/OEIS/A304330.lean +++ b/RealRooted/Applications/OEIS/A304330.lean @@ -357,9 +357,9 @@ theorem polynomial_interlaces (n : ℕ) : exact interlaces_one_linear (p := X) (by simp) | succ n => simp only [polynomial] - apply (qPolynomial_strictInterl_succ n).mul_X_both_of_roots_nonpos - (qPolynomial_isPF n).roots_nonpos - (qPolynomial_isPF (n + 1)).roots_nonpos |>.toInterlaces + apply (by + simpa using (qPolynomial_strictInterl_succ n).mul_X_sub_C_both 0 : + StrictInterl (X * qPolynomial n) (X * qPolynomial (n + 1))).toInterlaces rw [natDegree_mul X_ne_zero (qPolynomial_invariants n).2.2.ne_zero, natDegree_mul X_ne_zero (qPolynomial_invariants (n + 1)).2.2.ne_zero, natDegree_X, (qPolynomial_invariants n).1, diff --git a/RealRooted/Applications/OEIS/A304334.lean b/RealRooted/Applications/OEIS/A304334.lean index e94373c3c..dfcdb99fc 100644 --- a/RealRooted/Applications/OEIS/A304334.lean +++ b/RealRooted/Applications/OEIS/A304334.lean @@ -79,8 +79,7 @@ theorem interlaces_of_recurrence | succ n => rw [heq n, heq (n + 1)] have hstrict : StrictInterl (X * dividedRows n) (X * dividedRows (n + 1)) := - (strictInterl_dividedRows_succ n).mul_X_both_of_roots_nonpos - (dividedRows_roots_nonpos n) (dividedRows_roots_nonpos (n + 1)) + by simpa using (strictInterl_dividedRows_succ n).mul_X_sub_C_both 0 apply hstrict.toInterlaces have hspec := isNegativeSimple_generalRows 1 1 1 6 4 (by norm_num) (by norm_num) diff --git a/RealRooted/Applications/OEIS/CubicParentRows.lean b/RealRooted/Applications/OEIS/CubicParentRows.lean index c8c4fa296..2c7215aab 100644 --- a/RealRooted/Applications/OEIS/CubicParentRows.lean +++ b/RealRooted/Applications/OEIS/CubicParentRows.lean @@ -252,13 +252,13 @@ theorem a184883_splits (n : ℕ) : (a184883 n).Splits := by /-- Every A114123 row polynomial splits over `ℝ`. -/ theorem a114123_splits (n : ℕ) : (a114123 n).Splits := by - apply (DegreeDropReversal.splits_reflect_iff (a114123_natDegree_le n)).1 + apply (Polynomial.splits_reflect_iff (a114123_natDegree_le n)).1 rw [reflect_a114123_eq_a184883] exact a184883_splits n /-- Every A216182 row polynomial splits over `ℝ`. -/ theorem a216182_splits (n : ℕ) : (a216182 n).Splits := by - apply (DegreeDropReversal.splits_reflect_iff (a216182_natDegree_le n)).1 + apply (Polynomial.splits_reflect_iff (a216182_natDegree_le n)).1 rw [reflect_a216182_eq_odd_parent] exact (CubicParent.polynomial_splits (2 * n + 1)).C_mul (-1) diff --git a/RealRooted/ArrayPolynomialDeterminant.lean b/RealRooted/ArrayPolynomialDeterminant.lean index fc3ddb1af..c3eee6ba7 100644 --- a/RealRooted/ArrayPolynomialDeterminant.lean +++ b/RealRooted/ArrayPolynomialDeterminant.lean @@ -317,7 +317,7 @@ theorem arrayDetPolynomialFin_splits (N : ℕ) : (arrayDetPolynomialFin N).Splits := by rw [arrayDetPolynomialFin, det_one_add_X_smul_eq_reverse_charpoly_comp_neg_X] - apply (DegreeDropReversal.splits_reverse ?_).comp_of_natDegree_le_one + apply (Polynomial.Splits.reverse ?_).comp_of_natDegree_le_one · simp · exact charpoly_splits_of_complex_roots_real fun z hz => by obtain ⟨r, hr, hrz⟩ := arrayKernelShiftFin_complex_roots_nonneg N z hz diff --git a/RealRooted/ArrayPolynomialSchur.lean b/RealRooted/ArrayPolynomialSchur.lean index 38decbe43..cde327a23 100644 --- a/RealRooted/ArrayPolynomialSchur.lean +++ b/RealRooted/ArrayPolynomialSchur.lean @@ -117,7 +117,7 @@ theorem splits_reflect_of_isPFPolynomial {p : ℝ[X]} {n : ℕ} (hp : IsPFPolynomial p) (hp0 : p ≠ 0) (hn : p.natDegree ≤ n) : (reflect n p).Splits := by rw [DegreeDropReversal.reflect_eq_X_pow_mul_reverse p hn] - exact DegreeDropReversal.splits_X_pow_mul_reverse (hp.2.1.resolve_left hp0) n + exact Polynomial.Splits.X_pow_mul_reverse (hp.2.1.resolve_left hp0) n /-- **The array-polynomial conclusion, modulo the normalized input.** If the normalized polynomial `D` is Polya-frequency and the array row `P` is the diff --git a/RealRooted/Basic/AffineInterlacing.lean b/RealRooted/Basic/AffineInterlacing.lean index 3bfdea349..12c459598 100644 --- a/RealRooted/Basic/AffineInterlacing.lean +++ b/RealRooted/Basic/AffineInterlacing.lean @@ -74,11 +74,11 @@ lemma interlaces_comp_neg_X {g f : ℝ[X]} (h : Interlaces g f) : _ = Multiset.map Neg.neg g.roots := by rw [hgsr] · have hrslen : rs.length = f.natDegree := by have hc : (↑rs : Multiset ℝ).card = f.natDegree := by - rw [hfr, card_roots_of_splits hfs] + rw [hfr, Polynomial.splits_iff_card_roots.mp hfs] simpa using hc have hsslen : ss.length = g.natDegree := by have hc : (↑ss : Multiset ℝ).card = g.natDegree := by - rw [hgsr, card_roots_of_splits hgs] + rw [hgsr, Polynomial.splits_iff_card_roots.mp hgs] simpa using hc exact interlaces_reverse_map_neg hlist (by lia) diff --git a/RealRooted/Basic/Coefficients.lean b/RealRooted/Basic/Coefficients.lean index fc209a77e..c6089c2d4 100644 --- a/RealRooted/Basic/Coefficients.lean +++ b/RealRooted/Basic/Coefficients.lean @@ -34,12 +34,18 @@ lemma hasNonnegCoeffs_X : HasNonnegCoeffs (X : ℝ[X]) := by lemma hasNonnegCoeffs_C {a : ℝ} (ha : 0 ≤ a) : HasNonnegCoeffs (C a) := by rintro (_ | n) <;> simp [ha] -lemma nonnegCoeffs_C_mul {a : ℝ} (ha : 0 ≤ a) {p : ℝ[X]} +lemma hasNonnegCoeffs_C_mul {a : ℝ} (ha : 0 ≤ a) {p : ℝ[X]} (hp : HasNonnegCoeffs p) : HasNonnegCoeffs (C a * p) := by intro n simpa [coeff_C_mul] using mul_nonneg ha (hp n) +/-- Compatibility alias for `hasNonnegCoeffs_C_mul`. -/ +@[deprecated hasNonnegCoeffs_C_mul (since := "2026-10-21")] +lemma nonnegCoeffs_C_mul {a : ℝ} (ha : 0 ≤ a) {p : ℝ[X]} + (hp : HasNonnegCoeffs p) : HasNonnegCoeffs (C a * p) := + hasNonnegCoeffs_C_mul ha hp + lemma HasNonnegCoeffs.add {p q : ℝ[X]} (hp : HasNonnegCoeffs p) (hq : HasNonnegCoeffs q) : HasNonnegCoeffs (p + q) := fun n => by diff --git a/RealRooted/Basic/PolynomialFacts.lean b/RealRooted/Basic/PolynomialFacts.lean index d2c728963..14d68f072 100644 --- a/RealRooted/Basic/PolynomialFacts.lean +++ b/RealRooted/Basic/PolynomialFacts.lean @@ -28,9 +28,11 @@ theorem IsCoprime.not_isRoot_right {p q : R[X]} namespace RealRooted +@[deprecated Polynomial.splits_iff_card_roots +typeChanged (since := "2026-10-21")] lemma card_roots_of_splits {p : ℝ[X]} (h : p.Splits) : p.roots.card = p.natDegree := splits_iff_card_roots.mp h +@[deprecated Polynomial.splits_iff_card_roots +typeChanged (since := "2026-10-21")] lemma splits_of_card_roots {p : ℝ[X]} (h : p.roots.card = p.natDegree) : p.Splits := splits_iff_card_roots.mpr h @@ -56,23 +58,6 @@ lemma isRealRooted_mul {p q : ℝ[X]} (hp_ne : p ≠ 0) (hp_splits : p.Splits) (hq_ne : q ≠ 0) (hq_splits : q.Splits) : (p * q ≠ 0 ∧ (p * q).Splits) := ⟨mul_ne_zero hp_ne hq_ne, hp_splits.mul hq_splits⟩ -/-- Product transport for zero-aware splitting certificates. -/ -theorem mul_eq_zero_or_splits {p q : ℝ[X]} - (hp : p = 0 ∨ p.Splits) (hq : q = 0 ∨ q.Splits) : - p * q = 0 ∨ (p * q).Splits := by - rcases hp with rfl | hp - · simp - rcases hq with rfl | hq - · simp - · exact Or.inr (hp.mul hq) - -/-- Power transport for zero-aware splitting certificates. -/ -theorem pow_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) (n : ℕ) : - p ^ n = 0 ∨ (p ^ n).Splits := by - rcases hp with rfl | hp - · cases n <;> simp - · exact Or.inr (hp.pow n) - lemma coeff_X_sub_C_mul (r : ℝ) (q : ℝ[X]) (n : ℕ) : ((X - C r) * q).coeff n = (if n = 0 then 0 else q.coeff (n - 1)) - r * q.coeff n := by @@ -86,7 +71,8 @@ lemma exists_rightmost_root_of_isRealRooted let rs := p.roots.sort (· ≤ ·) have hrs_eq : (↑rs : Multiset ℝ) = p.roots := Multiset.sort_eq .. have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. - have hrs_len : rs.length = p.natDegree := by simp [rs, card_roots_of_splits hp_splits] + have hrs_len : rs.length = p.natDegree := by + simp [rs, Polynomial.splits_iff_card_roots.mp hp_splits] have hrs_ne : rs ≠ [] := by grind refine ⟨rs.getLast hrs_ne, ?_, ?_⟩ · have hr_mem : rs.getLast hrs_ne ∈ rs := List.getLast_mem hrs_ne diff --git a/RealRooted/Basic/RootLists.lean b/RealRooted/Basic/RootLists.lean index 2b76288f0..1b5ba8a88 100644 --- a/RealRooted/Basic/RootLists.lean +++ b/RealRooted/Basic/RootLists.lean @@ -100,7 +100,7 @@ lemma interleaves_of_listAlternates_of_length {ss rs : List ℝ} /-- In a nonempty right-hand list, each left entry of a weak interlacing is at most the corresponding later right entry. -/ -lemma listInterlaces_forall₂_le_tail : +private lemma listInterlaces_forall₂_le_tail : ∀ {ss rs : List ℝ} {r : ℝ}, ListInterlaces ss (r :: rs) → List.Forall₂ (fun s t : ℝ => s ≤ t) ss rs | [], [], _, _ => by simp @@ -110,6 +110,37 @@ lemma listInterlaces_forall₂_le_tail : rcases h with ⟨_, hsr₂, htail⟩ exact List.Forall₂.cons hsr₂ (listInterlaces_forall₂_le_tail htail) +/-- Every element of `ss` is at least the first element of the right-hand +list in a `ListInterlaces` relation. -/ +lemma listInterlaces_all_ge : + ∀ (ss rs : List ℝ) (r : ℝ), + ListInterlaces ss (r :: rs) → + ∀ s ∈ ss, r ≤ s + | [], _, _, _ => by simp + | [s], [], r, hint => by simp [ListInterlaces] at hint + | s :: ss', r₁ :: rs', r, hint => by + obtain ⟨hr, hsr₁, htail⟩ := hint + intro s' hs' + rcases List.mem_cons.mp hs' with rfl | hs'' + · lia + · exact le_trans (le_trans hr hsr₁) + (listInterlaces_all_ge ss' rs' r₁ htail s' hs'') + | _ :: _ :: _, [], _, hint => by simp [ListInterlaces] at hint + +/-- The left-hand list in a `ListInterlaces` relation is sorted. -/ +lemma pairwise_le_of_listInterlaces : + ∀ (ss rs : List ℝ), ListInterlaces ss rs → ss.Pairwise (· ≤ ·) + | [], _, _ => List.Pairwise.nil + | [_], _, _ => List.pairwise_singleton _ _ + | s₁ :: s₂ :: ss', r₁ :: r₂ :: rs', h => by + obtain ⟨_, hs₁r₂, htail⟩ := h + refine List.pairwise_cons.mpr ⟨?_, pairwise_le_of_listInterlaces _ _ htail⟩ + intro s hs + exact le_trans hs₁r₂ + (listInterlaces_all_ge (s₂ :: ss') rs' r₂ htail s hs) + | _ :: _ :: _, [], h => by simp [ListInterlaces] at h + | _ :: _ :: _, [_], h => by simp [ListInterlaces] at h + /-- Same-degree weak alternation gives pairwise coordinate inequalities. -/ lemma listAlternates_forall₂_le : ∀ {ss rs : List ℝ}, ListAlternates ss rs → diff --git a/RealRooted/BernsteinCone.lean b/RealRooted/BernsteinCone.lean index 1d6eb9b9a..b5fd53aa9 100644 --- a/RealRooted/BernsteinCone.lean +++ b/RealRooted/BernsteinCone.lean @@ -34,7 +34,7 @@ theorem hasNonnegCoeffs_cayleyTransform_of_roots_mem_Icc (hroots : ∀ r ∈ p.roots, r ∈ Set.Icc (-1 : ℝ) 0) : HasNonnegCoeffs (p.cayleyTransform n) := by rw [Polynomial.cayleyTransform_eq_rootFactorProduct hp hdeg] - apply nonnegCoeffs_C_mul hlead + apply hasNonnegCoeffs_C_mul hlead apply hasNonnegCoeffs_multisetProd intro q hq obtain ⟨r, hr, rfl⟩ := Multiset.mem_map.mp hq diff --git a/RealRooted/Bezoutian/StrictInterleaving.lean b/RealRooted/Bezoutian/StrictInterleaving.lean index f58f398a1..b9951633d 100644 --- a/RealRooted/Bezoutian/StrictInterleaving.lean +++ b/RealRooted/Bezoutian/StrictInterleaving.lean @@ -292,7 +292,7 @@ theorem StrictInterlSameDegree.toStrictInterl {p q : ℝ[X]} (h : StrictInterlSameDegree p q) : StrictInterl p q := by obtain ⟨⟨hp_ne, hp_splits⟩, ⟨hq_ne, hq_splits⟩, hdeg, h_inter⟩ := h have h_len : (p.roots.sort (· ≤ ·)).length = (q.roots.sort (· ≤ ·)).length := by - simp [card_roots_of_splits, *] + simp [Polynomial.splits_iff_card_roots.mp, *] rw [List.interleaves_reverse_reverse_of_length_eq_length h_len] at h_inter have h_le : List.Interleaves (· ≤ ·) (q.roots.sort (· ≤ ·)) (p.roots.sort (· ≤ ·)) := h_inter.mono fun _ _ hab ↦ le_of_lt hab diff --git a/RealRooted/BinaryRunTransformation/Anchor.lean b/RealRooted/BinaryRunTransformation/Anchor.lean index 719bd549e..9cd1083ce 100644 --- a/RealRooted/BinaryRunTransformation/Anchor.lean +++ b/RealRooted/BinaryRunTransformation/Anchor.lean @@ -268,11 +268,11 @@ theorem oddPathReverse_roots_nodup (d : ℕ) : theorem pathMatchingPolynomial_splits (N : ℕ) : (pathMatchingPolynomial N).Splits := by obtain ⟨d, rfl | rfl⟩ := Nat.even_or_odd' N - · apply (DegreeDropReversal.splits_reflect_iff (N := d) (by + · apply (Polynomial.splits_reflect_iff (N := d) (by rw [natDegree_pathMatchingPolynomial] norm_num)).mp exact evenPathReverse_splits d - · apply (DegreeDropReversal.splits_reflect_iff (N := d) (by + · apply (Polynomial.splits_reflect_iff (N := d) (by rw [natDegree_pathMatchingPolynomial] norm_num [Nat.add_div])).mp exact oddPathReverse_splits d diff --git a/RealRooted/BinaryRunTransformation/Continuation.lean b/RealRooted/BinaryRunTransformation/Continuation.lean index 4ca254ad7..eac6fa4c2 100644 --- a/RealRooted/BinaryRunTransformation/Continuation.lean +++ b/RealRooted/BinaryRunTransformation/Continuation.lean @@ -623,9 +623,12 @@ private theorem isPFPolynomial_binaryRunTransform_of_le_three mul_nonneg (hp.hasNonnegCoeffs 1) htail, sq_nonneg (2 * p.coeff 2 / 3 + p.coeff 3)] have hqSplit : q.Splits := by - apply splits_of_natDegree_le_two_of_discrim_nonneg hqdeg - unfold discrim - nlinarith + by_cases hq2 : q.natDegree = 2 + · apply splits_of_natDegree_eq_two_of_discrim_nonneg hq2 + unfold discrim + nlinarith + · apply Polynomial.Splits.of_natDegree_le_one + lia exact IsPFPolynomial.of_realRooted_nonneg hqnn hqSplit · have hn2 : n ≤ 2 := by lia apply IsPFPolynomial.of_realRooted_nonneg hqnn diff --git a/RealRooted/BinaryRunTransformation/CrossLength.lean b/RealRooted/BinaryRunTransformation/CrossLength.lean index 0750b6e1e..b7056f064 100644 --- a/RealRooted/BinaryRunTransformation/CrossLength.lean +++ b/RealRooted/BinaryRunTransformation/CrossLength.lean @@ -59,7 +59,7 @@ theorem strictInterl_C_mul_sub_two_theta_self {N : ℕ} {g : ℝ[X]} have hPnn : HasNonnegCoeffs (polarTheta d g) := (polarTheta_preserves_pf hg le_rfl).hasNonnegCoeffs have hP2 : StrictInterl (C 2 * polarTheta d g) g := hpd.C_mul_left two_ne_zero - have hP2nn : HasNonnegCoeffs (C 2 * polarTheta d g) := nonnegCoeffs_C_mul (by norm_num) hPnn + have hP2nn : HasNonnegCoeffs (C 2 * polarTheta d g) := hasNonnegCoeffs_C_mul (by norm_num) hPnn have heq : C (N : ℝ) * g - C 2 * theta g = C 2 * polarTheta d g + C ((N : ℝ) - 2 * d) * g := by simp only [polarTheta, C_sub, C_mul, map_natCast, map_ofNat] @@ -81,7 +81,7 @@ theorem strictInterl_C_mul_sub_two_theta_self {N : ℕ} {g : ℝ[X]} refine ⟨StrictInterl.add_of_right_of_posLeadingCoeff hP2 hgg (hP2nn.pos_leadingCoeff hP2.1.1) (hasPosLeadingCoeff_C_mul hpos (hgnn.pos_leadingCoeff hg_ne)), ?_⟩ - exact hP2nn.add (nonnegCoeffs_C_mul hpos.le hgnn) + exact hP2nn.add (hasNonnegCoeffs_C_mul hpos.le hgnn) /-- Cross-length transport for the binary-run transformation: `J_n((N - 2Θ) g) ≪ J_{n+1}(g)` for `N = n + 1`, a PF polynomial `g` with diff --git a/RealRooted/BinaryRunTransformation/MultiplierMotzkin.lean b/RealRooted/BinaryRunTransformation/MultiplierMotzkin.lean index 550f007e2..3de60824e 100644 --- a/RealRooted/BinaryRunTransformation/MultiplierMotzkin.lean +++ b/RealRooted/BinaryRunTransformation/MultiplierMotzkin.lean @@ -464,7 +464,7 @@ theorem motzkinWeightedRow_inv_ascPochhammer_succ_strictInterl {α : ℝ} (hα : have hself := strictInterl_self_thetac hg (by rw [hdeg]; lia) hα rw [← motzkinWeightedInput_inv_ascPochhammer_shift hα n] at hself have hCnn : HasNonnegCoeffs (C α * motzkinWeightedInput γ n) := - nonnegCoeffs_C_mul hα.le (motzkinWeightedInput_isPFPolynomial hγPF n).hasNonnegCoeffs + hasNonnegCoeffs_C_mul hα.le (motzkinWeightedInput_isPFPolynomial hγPF n).hasNonnegCoeffs have hT := strictInterl_binaryRunTransform (n := n) hself hg.hasNonnegCoeffs hCnn ((natDegree_C_mul_le _ _).trans (by rw [natDegree_motzkinWeightedInput hγpos]; lia)) rw [binaryRunTransform_C_mul] at hT diff --git a/RealRooted/BrandenLeite/ChainPolynomial.lean b/RealRooted/BrandenLeite/ChainPolynomial.lean index c6d06da50..e0cc199cd 100644 --- a/RealRooted/BrandenLeite/ChainPolynomial.lean +++ b/RealRooted/BrandenLeite/ChainPolynomial.lean @@ -153,7 +153,7 @@ private theorem scale_range_interlacing · intro p hp rcases List.mem_map.mp hp with ⟨j, hj, rfl⟩ have hjq : j < q := by simpa using hj - exact nonnegCoeffs_C_mul (ha j hjq) + exact hasNonnegCoeffs_C_mul (ha j hjq) (hf.nonnegCoeffs _ (List.mem_map.mpr ⟨j, hj, rfl⟩)) · intro p hp hp_ne rcases List.mem_map.mp hp with ⟨j, hj, rfl⟩ @@ -358,13 +358,13 @@ theorem interl_chainPolynomial_succ (resolution.lambda_nonneg n j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (resolution.lambda_nonneg n j hjn) + exact hasNonnegCoeffs_C_mul (resolution.lambda_nonneg n j hjn) (hrow.nonnegCoeffs _ (hmem j hjn)) have hSnn : HasNonnegCoeffs S := by apply hasNonnegCoeffs_finsetSum intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (resolution.lambda_nonneg n j hjn) + exact hasNonnegCoeffs_C_mul (resolution.lambda_nonneg n j hjn) (hrow.nonnegCoeffs _ (hmem j hjn)) have hFn : F n = chainPolynomial R n := subdivisionOperator_resolutionPolynomial_diagonal resolution n diff --git a/RealRooted/BrandenVecchi/ChowInterlacingQuotient.lean b/RealRooted/BrandenVecchi/ChowInterlacingQuotient.lean index 4e6253249..febc0ccc2 100644 --- a/RealRooted/BrandenVecchi/ChowInterlacingQuotient.lean +++ b/RealRooted/BrandenVecchi/ChowInterlacingQuotient.lean @@ -198,7 +198,7 @@ theorem chowS_nonnegCoeffs_and_strictInterl_of_triple intro r hr apply hdiff_le_one r apply (mem_roots houter.2.1.1).mpr - exact IsRoot.of_dvd hS_dvd ((mem_roots hS_ne).mp hr) + exact ((mem_roots hS_ne).mp hr).dvd hS_dvd have hg_le_one : ∀ r ∈ g.roots, r ≤ 1 := by intro r hr linarith [hg_nonpos r hr] diff --git a/RealRooted/BrandenVecchi/ChowInterlacingSign.lean b/RealRooted/BrandenVecchi/ChowInterlacingSign.lean index e3acac303..b020c89c3 100644 --- a/RealRooted/BrandenVecchi/ChowInterlacingSign.lean +++ b/RealRooted/BrandenVecchi/ChowInterlacingSign.lean @@ -60,9 +60,9 @@ theorem leadingCoeff_cross_mul_eq_of_strictInterl_sameDegree_of_nonneg_of_eval_c rcases hstrictInterl with ⟨hf, hg, ss, rs, _hss_sorted, _hrs_sorted, hss_eq, hrs_eq, hshape⟩ have hlen_ss : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hlen_rs : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have halt : ListAlternates ss rs := by simp_all have hpair : List.Forall₂ (fun x y : ℝ => x ≤ y) ss rs := listAlternates_forall₂_le halt @@ -103,8 +103,8 @@ theorem leadingCoeff_cross_mul_eq_of_strictInterl_sameDegree_of_nonneg_of_eval_c have hflc : 0 < f.leadingCoeff := hfnn.pos_leadingCoeff hf.1 have hglc : 0 < g.leadingCoeff := hgnn.pos_leadingCoeff hg.1 have hprod : (rs.map (0 - ·)).prod = (ss.map (0 - ·)).prod := by - rw [eval_eq_leadingCoeff_mul_prod_sub hf.2 0, - eval_eq_leadingCoeff_mul_prod_sub hg.2 0, ← hss_eq, ← hrs_eq] at hcross + rw [Polynomial.Splits.eval_eq_prod_roots hf.2 0, + Polynomial.Splits.eval_eq_prod_roots hg.2 0, ← hss_eq, ← hrs_eq] at hcross simp only [Multiset.map_coe, Multiset.prod_coe] at hcross have hcancel : f.leadingCoeff * g.leadingCoeff * (rs.map (0 - ·)).prod = f.leadingCoeff * g.leadingCoeff * (ss.map (0 - ·)).prod := by diff --git a/RealRooted/BrandenVecchi/ChowResolutionInterlacing.lean b/RealRooted/BrandenVecchi/ChowResolutionInterlacing.lean index bdf267b2a..59208d310 100644 --- a/RealRooted/BrandenVecchi/ChowResolutionInterlacing.lean +++ b/RealRooted/BrandenVecchi/ChowResolutionInterlacing.lean @@ -287,7 +287,7 @@ theorem resolvedChowCombination_endpoint_interl exact Interl.C_mul_right_of_nonneg (hleft j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) + exact hasNonnegCoeffs_C_mul (ha j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) · apply Interl.finsetSum_right_of_nonneg · intro j hj @@ -295,7 +295,7 @@ theorem resolvedChowCombination_endpoint_interl exact Interl.C_mul_left_of_nonneg (hright j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) + exact hasNonnegCoeffs_C_mul (ha j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) /-- Strict endpoint form of Theorem 4.16. All three nonvanishing hypotheses diff --git a/RealRooted/BrandenVecchi/ChowTotallyNonneg.lean b/RealRooted/BrandenVecchi/ChowTotallyNonneg.lean index d6113dab5..954122b60 100644 --- a/RealRooted/BrandenVecchi/ChowTotallyNonneg.lean +++ b/RealRooted/BrandenVecchi/ChowTotallyNonneg.lean @@ -164,7 +164,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs (hdirectReflect 0 (Nat.zero_le n) j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) + exact hasNonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) have hFref0 : Interl F ((d 0).reflect n) := by dsimp only [F, resolvedChowWeightSum] apply Interl.finsetSum_right_of_nonneg @@ -174,7 +174,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs (hdirectReflect j hjn 0 (Nat.zero_le n)) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) (hdnn j hjn) + exact hasNonnegCoeffs_C_mul (ha j hjn) (hdnn j hjn) have hrefFref0 : Interl (F.reflect n) ((d 0).reflect n) := by rw [hreflectF] apply Interl.finsetSum_right_of_nonneg @@ -183,7 +183,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs exact Interl.C_mul_left_of_nonneg (hreflectLeft j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) + exact hasNonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) have hFrefn : Interl F ((d n).reflect n) := by dsimp only [F, resolvedChowWeightSum] apply Interl.finsetSum_right_of_nonneg @@ -193,7 +193,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs (hdirectReflect j hjn n le_rfl) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) (hdnn j hjn) + exact hasNonnegCoeffs_C_mul (ha j hjn) (hdnn j hjn) have hnrefF : Interl (d n) (F.reflect n) := by rw [hreflectF] apply Interl.finsetSum_left_of_nonneg @@ -203,7 +203,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs (hdirectReflect n le_rfl j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) + exact hasNonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) have hrefnrefF : Interl ((d n).reflect n) (F.reflect n) := by rw [hreflectF] apply Interl.finsetSum_left_of_nonneg @@ -212,7 +212,7 @@ private theorem resolvedChowWeightSum_endpoint_pairs exact Interl.C_mul_right_of_nonneg (hreflectRight j hjn) (ha j hjn) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) + exact hasNonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) have hFrefF : Interl F (F.reflect n) := by rw [hreflectF] dsimp only [F, resolvedChowWeightSum] @@ -225,10 +225,10 @@ private theorem resolvedChowWeightSum_endpoint_pairs (ha j hjn) · intro i hi have hin : i ≤ n := by simpa using Finset.mem_range.mp hi - exact nonnegCoeffs_C_mul (ha i hin) (hdnn i hin) + exact hasNonnegCoeffs_C_mul (ha i hin) (hdnn i hin) · intro j hj have hjn : j ≤ n := by simpa using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) + exact hasNonnegCoeffs_C_mul (ha j hjn) ((hdnn j hjn).reflect n) constructor · exact reflectionInterlacing_pair_of_relations (hdpf 0 (Nat.zero_le n)) hFpf (hddeg 0 (Nat.zero_le n)) hFdeg diff --git a/RealRooted/BrandenVecchi/ReflectionInterlacing.lean b/RealRooted/BrandenVecchi/ReflectionInterlacing.lean index 27aab2c69..d20eea270 100644 --- a/RealRooted/BrandenVecchi/ReflectionInterlacing.lean +++ b/RealRooted/BrandenVecchi/ReflectionInterlacing.lean @@ -57,7 +57,7 @@ theorem IsInterlacingSeq0NonnegRealRooted.nonnegScalarMultiples have hi : i.val < fs.length := by simp [hlen] rcases hscale.get hi i.isLt with ⟨a, ha, hia⟩ rw [hia] - exact nonnegCoeffs_C_mul ha + exact hasNonnegCoeffs_C_mul ha (hfs.nonnegCoeffs (fs.get ⟨i, hi⟩) (List.get_mem _ _)) · intro g hg hg_ne rcases List.get_of_mem hg with ⟨i, rfl⟩ diff --git a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh.lean b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh.lean index 493410443..7c9850a76 100644 --- a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh.lean +++ b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh.lean @@ -357,10 +357,10 @@ theorem IsStrictlyHurwitzStable.strictInterl_parts_of_oddShape by_cases hdegreeZero : odd.natDegree = 0 · have hevenDegreeZero : even.natDegree = 0 := hdegree.trans hdegreeZero have hoddRoots : odd.roots = 0 := by - rw [← Multiset.card_eq_zero, card_roots_of_splits hoddSplits, + rw [← Multiset.card_eq_zero, Polynomial.splits_iff_card_roots.mp hoddSplits, hdegreeZero] have hevenRoots : even.roots = 0 := by - rw [← Multiset.card_eq_zero, card_roots_of_splits hevenSplits, + rw [← Multiset.card_eq_zero, Polynomial.splits_iff_card_roots.mp hevenSplits, hevenDegreeZero] exact ⟨⟨hodd.ne_zero, hoddSplits⟩, ⟨heven.ne_zero, hevenSplits⟩, [], [], by simp, by simp, by simp [hoddRoots], by simp [hevenRoots], @@ -512,9 +512,10 @@ theorem IsStrictlyHurwitzStable.routhReducedOddPart_ne_zero_of_oddShape h.coeff_zero_pos_parts_of_oddShape hodd heven hdegree have hoddSplits := (h.splits_parts_of_oddShape hodd heven hdegree).1 - obtain ⟨r, hroot⟩ := - exists_isRoot_of_isRealRooted_of_not_isUnit hodd.ne_zero hoddSplits - (Polynomial.not_isUnit_of_natDegree_pos odd hdegreePos) + obtain ⟨r, hroot⟩ : ∃ r : ℝ, odd.IsRoot r := by + simpa [Polynomial.IsRoot.def] using hoddSplits.exists_eval_eq_zero + (degree_pos_of_ne_zero_of_nonunit hodd.ne_zero + (Polynomial.not_isUnit_of_natDegree_pos odd hdegreePos)).ne' intro hred apply h.noCommonRoot_parts_of_hasNonnegCoeffs hodd.ne_zero hoddnn r refine ⟨hroot, ?_⟩ diff --git a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/ProperPosition.lean b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/ProperPosition.lean index 18a3bb6b5..1bc6b9d10 100644 --- a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/ProperPosition.lean +++ b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/ProperPosition.lean @@ -206,7 +206,7 @@ theorem IsStrictlyHurwitzStable.strictInterl_routhReducedOddPart_of_oddShape refine Multiset.prod_pos ?_ simp_all have hdivPos : HasPosLeadingCoeff q.divX := by - rw [eval_eq_leadingCoeff_mul_prod_sub hdivSplits 0] at hdivEval + rw [Polynomial.Splits.eval_eq_prod_roots hdivSplits 0] at hdivEval exact (mul_pos_iff_of_pos_right hprodPos).mp hdivEval have hdivnn : HasNonnegCoeffs q.divX := ((hasNonnegCoeffs_iff_pos_leadingCoeff_and_roots_nonpos hdivSplits).2 diff --git a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/Reverse.lean b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/Reverse.lean index 43a6b1c95..b527524f1 100644 --- a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/Reverse.lean +++ b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/Reverse.lean @@ -59,7 +59,7 @@ theorem IsStrictlyHurwitzStable.oddEvenPolynomial_of_routhReducedPolynomial even_eq_C_mul_odd_add_X_mul_routhReducedOddPart c odd even h0 have hevennn : HasNonnegCoeffs even := by rw [heq] - exact (nonnegCoeffs_C_mul hc.le hoddnn).add hrednn.X_mul + exact (hasNonnegCoeffs_C_mul hc.le hoddnn).add hrednn.X_mul have heven0 : even.coeff 0 ≠ 0 := by rw [h0] exact mul_ne_zero hc.ne' hodd0.ne' diff --git a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/WeakReverse.lean b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/WeakReverse.lean index 5dc268544..566c352b7 100644 --- a/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/WeakReverse.lean +++ b/RealRooted/ClassicalHurwitzMatrix/Stability/Routh/WeakReverse.lean @@ -275,7 +275,7 @@ theorem IsHurwitzStable.oddEvenPolynomial_of_routhReducedPolynomial_of_natDegree exact hasNonnegCoeffs_oddEvenPolynomial hoddnn (by rw [even_eq_C_mul_odd_add_X_mul_routhReducedOddPart c odd even h0] - exact (nonnegCoeffs_C_mul hc.le hoddnn).add hrednn.X_mul) + exact (hasNonnegCoeffs_C_mul hc.le hoddnn).add hrednn.X_mul) · have hlimit := isRightHalfPlaneStable_of_monic_tendsto_eval hp₀ne hPmonic hPdegree hPstable hPeval intro z hz hroot diff --git a/RealRooted/CoefficientShape.lean b/RealRooted/CoefficientShape.lean index 1558acb7f..4db19931d 100644 --- a/RealRooted/CoefficientShape.lean +++ b/RealRooted/CoefficientShape.lean @@ -358,7 +358,7 @@ theorem hasUltraLogConcaveCoeffs_of_hasNonnegCoeffs_of_eq_zero_or_splits {p : · intro k hk0 hkd set t := p.roots.map Neg.neg with ht_def have htcard : Multiset.card t = p.natDegree := by - rw [ht_def, Multiset.card_map, card_roots_of_splits hsplits] + rw [ht_def, Multiset.card_map, Polynomial.splits_iff_card_roots.mp hsplits] have hc1 := coeff_eq_leadingCoeff_mul_esymm_neg_roots hsplits (k := k - 1) (by lia) have hck := coeff_eq_leadingCoeff_mul_esymm_neg_roots hsplits (k := k) (by lia) have hc2 := coeff_eq_leadingCoeff_mul_esymm_neg_roots hsplits (k := k + 1) (by lia) diff --git a/RealRooted/CombinatorialExamples/Motzkin.lean b/RealRooted/CombinatorialExamples/Motzkin.lean index 4e6070e96..de838f4c6 100644 --- a/RealRooted/CombinatorialExamples/Motzkin.lean +++ b/RealRooted/CombinatorialExamples/Motzkin.lean @@ -162,7 +162,6 @@ lemma strictInterl_motzkin_zero_one : lemma strictInterl_motzkin_shifted_succ {n : Nat} (hprev : StrictInterl (motzkin n) (motzkin (n + 1))) - (hle_n : ∀ r ∈ (motzkin n).roots, r ≤ motzkinShift) (hle_succ : ∀ r ∈ (motzkin (n + 1)).roots, r ≤ motzkinShift) : StrictInterl (motzkin (n + 2)) ((X - C motzkinShift) * motzkin (n + 1)) := by have hscalarA_pos : 0 < motzkinCoeffA n := by rw [motzkinCoeffA]; positivity @@ -177,7 +176,7 @@ lemma strictInterl_motzkin_shifted_succ {n : Nat} have hright_core : StrictInterl ((X - C motzkinShift) * motzkin n) ((X - C motzkinShift) * motzkin (n + 1)) := - hprev.mul_X_sub_C_both_of_roots_le motzkinShift hle_n hle_succ + hprev.mul_X_sub_C_both motzkinShift have hright : StrictInterl (C (motzkinCoeffB n) * ((X - C motzkinShift) * motzkin n)) ((X - C motzkinShift) * motzkin (n + 1)) := @@ -252,7 +251,7 @@ theorem strictInterl_motzkin_succ_and_roots_le : rcases strictInterl_motzkin_succ_and_roots_le n with ⟨hprev, hle_n, hle_succ⟩ have hshift : StrictInterl (motzkin (n + 2)) ((X - C motzkinShift) * motzkin (n + 1)) := - strictInterl_motzkin_shifted_succ hprev hle_n hle_succ + strictInterl_motzkin_shifted_succ hprev hle_succ have hright_le : ∀ r ∈ ((X - C motzkinShift) * motzkin (n + 1)).roots, r ≤ motzkinShift := roots_le_X_sub_C_mul hprev.2.1.2 hle_succ diff --git a/RealRooted/CombinatorialExamples/MultisetEulerianNarayana/GammaOperator.lean b/RealRooted/CombinatorialExamples/MultisetEulerianNarayana/GammaOperator.lean index 07fbf1a54..45a6c7eb5 100644 --- a/RealRooted/CombinatorialExamples/MultisetEulerianNarayana/GammaOperator.lean +++ b/RealRooted/CombinatorialExamples/MultisetEulerianNarayana/GammaOperator.lean @@ -330,7 +330,7 @@ private theorem simpleNegRooted_gammaOperator_zero exact hasPosLeadingCoeff_C_mul hb (hasPosLeadingCoeff_X_add_C _) have hpnn : HasNonnegCoeffs p := by rw [hp_eq] - exact nonnegCoeffs_C_mul hb.le (hasNonnegCoeffs_X_add_C (by positivity)) + exact hasNonnegCoeffs_C_mul hb.le (hasNonnegCoeffs_X_add_C (by positivity)) have hp0 : 0 < p.coeff 0 := by simp [p] have hbase : SimpleNegRooted p 1 := diff --git a/RealRooted/CombinatorialExamples/PeakValues/WeightedInterleaving.lean b/RealRooted/CombinatorialExamples/PeakValues/WeightedInterleaving.lean index 547464e39..74f4b0549 100644 --- a/RealRooted/CombinatorialExamples/PeakValues/WeightedInterleaving.lean +++ b/RealRooted/CombinatorialExamples/PeakValues/WeightedInterleaving.lean @@ -224,7 +224,7 @@ theorem peakValueWeightedDiagonal_consecutive_strictInterl_of_stable have hA0 : A ≠ 0 := by rw [hAeq]; exact mul_ne_zero (by norm_num) hlower0 have hApos : HasPosLeadingCoeff A := hAnn.pos_leadingCoeff hA0 have hDnn : HasNonnegCoeffs D := - nonnegCoeffs_C_mul (hwpos none).le + hasNonnegCoeffs_C_mul (hwpos none).le (commonPhaseRestriction_hasNonnegCoeffs hDQnn w fun j => (hwpos j).le) have hD0 : D ≠ 0 := by diff --git a/RealRooted/CombinatorialExamples/SingletonFreeSetPartitions.lean b/RealRooted/CombinatorialExamples/SingletonFreeSetPartitions.lean index 6635b9aa3..e386b4ee3 100644 --- a/RealRooted/CombinatorialExamples/SingletonFreeSetPartitions.lean +++ b/RealRooted/CombinatorialExamples/SingletonFreeSetPartitions.lean @@ -207,7 +207,7 @@ lemma strictInterl_singletonFreeSetPartitions_three_four : have hlin_nonneg : HasNonnegCoeffs (1 + C (3 : ℝ) * X) := by have hX_nonneg : HasNonnegCoeffs (X : ℝ[X]) := by rintro (_ | _ | m) <;> simp [coeff_X] have hCX_nonneg : HasNonnegCoeffs (C (3 : ℝ) * X) := - nonnegCoeffs_C_mul (by simp) hX_nonneg + hasNonnegCoeffs_C_mul (by simp) hX_nonneg exact fun m => add_nonneg (hasNonnegCoeffs_one m) (hCX_nonneg m) have hmul : StrictInterl (X * (1 : ℝ[X])) (X * (1 + C (3 : ℝ) * X)) := by diff --git a/RealRooted/CombinatorialExamples/SturmDerangementsExc.lean b/RealRooted/CombinatorialExamples/SturmDerangementsExc.lean index 6f936c85c..8dcfa201b 100644 --- a/RealRooted/CombinatorialExamples/SturmDerangementsExc.lean +++ b/RealRooted/CombinatorialExamples/SturmDerangementsExc.lean @@ -448,9 +448,7 @@ lemma strictInterl_sturmDerangementsExc_affine_mul_X {n : Nat} (hn : 2 ≤ n) lemma strictInterl_X_mul_affine_sturmDerangementsExc {n : Nat} (hn : 2 ≤ n) (hrr : (sturmDerangementsExc n).Splits) : StrictInterl (X * affineSturmDerangementsExc n) (X * sturmDerangementsExc n) := - (strictInterl_affine_sturmDerangementsExc hn hrr).mul_X_both_of_nonneg - (affine_sturmDerangementsExc_nonnegCoeffs hn) - (sturmDerangementsExc_nonnegCoeffs n) + by simpa using (strictInterl_affine_sturmDerangementsExc hn hrr).mul_X_sub_C_both 0 lemma strictInterl_X_mul_lowerTerm_sturmDerangementsExc {n : Nat} (hn : 3 ≤ n) (hstrictInterl : StrictInterl (sturmDerangementsExc (n - 1)) (sturmDerangementsExc n)) : @@ -461,9 +459,8 @@ lemma strictInterl_X_mul_lowerTerm_sturmDerangementsExc {n : Nat} (hn : 3 ≤ n) strictInterl_lowerTerm_sturmDerangementsExc (by lia) hstrictInterl have hlower_nonneg : HasNonnegCoeffs (C (n : ℝ) * sturmDerangementsExc (n - 1)) := - nonnegCoeffs_C_mul (by positivity) (sturmDerangementsExc_nonnegCoeffs (n - 1)) - exact hlower.mul_X_both_of_nonneg hlower_nonneg - (sturmDerangementsExc_nonnegCoeffs n) + hasNonnegCoeffs_C_mul (by positivity) (sturmDerangementsExc_nonnegCoeffs (n - 1)) + simpa using hlower.mul_X_sub_C_both 0 /-- The two inner summands in the derangement recurrence both precede `X * P_n`. This matches the main induction-step input in the human proof. -/ diff --git a/RealRooted/CombinatorialExamples/SuperEulerian.lean b/RealRooted/CombinatorialExamples/SuperEulerian.lean index 86d47bfa8..994d34738 100644 --- a/RealRooted/CombinatorialExamples/SuperEulerian.lean +++ b/RealRooted/CombinatorialExamples/SuperEulerian.lean @@ -78,7 +78,7 @@ theorem hasNonnegCoeffs_of_splits_of_roots_nonpos_of_coeff_zero_pos {p : ℝ[X]} have hP : HasNonnegCoeffs ((p.roots.map (X - C ·)).prod) := hasNonnegCoeffs_multiset_prod_X_sub_C p.roots hr have hp : p = C p.leadingCoeff * (p.roots.map (X - C ·)).prod := - (C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hs)).symm + (C_leadingCoeff_mul_prod_multiset_X_sub_C (Polynomial.splits_iff_card_roots.mp hs)).symm have hc := congrArg (fun q => q.coeff 0) hp simp only [coeff_C_mul] at hc have hlc : 0 < p.leadingCoeff := by @@ -87,7 +87,7 @@ theorem hasNonnegCoeffs_of_splits_of_roots_nonpos_of_coeff_zero_pos {p : ℝ[X]} have := mul_nonpos_of_nonpos_of_nonneg hneg (hP 0) linarith rw [hp] - exact nonnegCoeffs_C_mul hlc.le hP + exact hasNonnegCoeffs_C_mul hlc.le hP private lemma gamma_expansion_remainder {d : ℕ} {p : ℝ[X]} (hdeg : p.natDegree ≤ d) (hfix : idTransform d p = p) (hd : 1 ≤ d) : @@ -164,8 +164,10 @@ theorem orderedRoot_lt_of_strictInterl {p q : ℝ[X]} {n : ℕ} (h : StrictInter (hp : p.natDegree = n) (hq : q.natDegree = n) (hno : ∀ r, p.IsRoot r → ¬ q.IsRoot r) (i : Fin n) : orderedRoot p n i < orderedRoot q n i := by refine lt_of_le_of_ne (h.orderedRoot_le hp hq i) fun heq => ?_ - have hpm := orderedRoot_mem_roots (n := n) (by rw [card_roots_of_splits h.1.2, hp]) i - have hqm := orderedRoot_mem_roots (n := n) (by rw [card_roots_of_splits h.2.1.2, hq]) i + have hpm := orderedRoot_mem_roots (n := n) + (by rw [Polynomial.splits_iff_card_roots.mp h.1.2, hp]) i + have hqm := orderedRoot_mem_roots (n := n) + (by rw [Polynomial.splits_iff_card_roots.mp h.2.1.2, hq]) i rw [← heq] at hqm exact hno _ ((mem_roots h.1.1).mp hpm) ((mem_roots h.2.1.1).mp hqm) @@ -1006,8 +1008,10 @@ private lemma strictInterl_superEulerian_step {l m : ℕ} have hVU : StrictInterl V U := (interl_polarThetaIterate_thetaPlusOneIterate l m).toStrictInterl_of_ne hV.pos.ne_zero hU.pos.ne_zero - have hEcard : E.roots.card = m := by rw [card_roots_of_splits hE.splits, hE.natDegree_eq] - have hUcard : U.roots.card = m := by rw [card_roots_of_splits hU.splits, hU.natDegree_eq] + have hEcard : E.roots.card = m := by + rw [Polynomial.splits_iff_card_roots.mp hE.splits, hE.natDegree_eq] + have hUcard : U.roots.card = m := by + rw [Polynomial.splits_iff_card_roots.mp hU.splits, hU.natDegree_eq] have hno : ∀ r, E.IsRoot r → ¬ U.IsRoot r := not_isRoot_of_orderedRoot_chain hE0 hU.pos.ne_zero hEcard hUcard (hE.orderedRoot_lt_iterateThetaPlusOne l) diff --git a/RealRooted/CommonInterleaver/PairBridge/Reduction/CommonRoot.lean b/RealRooted/CommonInterleaver/PairBridge/Reduction/CommonRoot.lean index 7fed43d28..fd0ea7c61 100644 --- a/RealRooted/CommonInterleaver/PairBridge/Reduction/CommonRoot.lean +++ b/RealRooted/CommonInterleaver/PairBridge/Reduction/CommonRoot.lean @@ -59,7 +59,7 @@ private lemma hasNonnegCoeffs_quotient_add_right_of_common_root have hp_rr : (p ≠ 0 ∧ p.Splits) := by simpa [p] using hfg.isRealRooted_add_right hμ have hp_nn : HasNonnegCoeffs p := by dsimp [p] - exact hfnn.add (nonnegCoeffs_C_mul hμ.le hgnn) + exact hfnn.add (hasNonnegCoeffs_C_mul hμ.le hgnn) have hp_eq : p = (X - C r) * (qf + C μ * qg) := by grind have hq_ne : qf + C μ * qg ≠ 0 := by simp_all have hq_rr : ((qf + C μ * qg) ≠ 0 ∧ (qf + C μ * qg).Splits) := diff --git a/RealRooted/CommonInterleaver/RootCountCombinatorics.lean b/RealRooted/CommonInterleaver/RootCountCombinatorics.lean index c9f5302d5..9f4856486 100644 --- a/RealRooted/CommonInterleaver/RootCountCombinatorics.lean +++ b/RealRooted/CommonInterleaver/RootCountCombinatorics.lean @@ -44,7 +44,7 @@ theorem card_roots_filter_gt_add_le_of_splits {p : ℝ[X]} (hp : p.Splits) intro r _ exact ⟨fun h => not_lt.mpr h, fun h => not_lt.mp h⟩ rw [hcompl, ← Multiset.card_add, Multiset.filter_add_not, - card_roots_of_splits hp] + Polynomial.splits_iff_card_roots.mp hp] private theorem int_card_roots_filter_gt_add_le_of_splits {p : ℝ[X]} (hp : p.Splits) (x : ℝ) : @@ -169,8 +169,9 @@ theorem succDegreeRootCrossing_of_rootCount (rootSeqDesc g).getD j 0 ≤ (rootSeqDesc f).getD (j - 1) 0) ∧ (∀ j, 1 ≤ j → j < f.natDegree → (rootSeqDesc f).getD j 0 ≤ (rootSeqDesc g).getD (j - 1) 0) := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree + 1 := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree + 1 := by + rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact succRootCrossing_of_count_le_two hMcard hNcard hcount /-- Converse root-count bridge from successor-degree descending-root crossing @@ -190,8 +191,9 @@ theorem succDegreeRootCount_of_rootCrossing (g.roots.filter (· ≤ x)).card ≤ 0 ∧ ((g.roots.filter (· ≤ x)).card : ℤ) - (f.roots.filter (· ≤ x)).card ≤ 2 := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree + 1 := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree + 1 := by + rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact count_le_two_of_succRootCrossing hMcard hNcard hcross /-- Root-count bridge from the upper-threshold formulation to the succ-degree @@ -206,8 +208,9 @@ theorem succDegreeRootCrossing_of_rootCountAbove (rootSeqDesc g).getD j 0 ≤ (rootSeqDesc f).getD (j - 1) 0) ∧ (∀ j, 1 ≤ j → j < f.natDegree → (rootSeqDesc f).getD j 0 ≤ (rootSeqDesc g).getD (j - 1) 0) := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree + 1 := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree + 1 := by + rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact succRootCrossing_of_count_gt_diff_le_one hMcard hNcard hcount /-- Convert the upper-threshold succ-degree root-count formulation into the @@ -221,8 +224,9 @@ theorem succDegreeRootCount_of_rootCountAbove ∀ x : ℝ, ((f.roots.filter (· ≤ x)).card : ℤ) - (g.roots.filter (· ≤ x)).card ≤ 0 ∧ ((g.roots.filter (· ≤ x)).card : ℤ) - (f.roots.filter (· ≤ x)).card ≤ 2 := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree + 1 := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree + 1 := by + rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact count_le_two_of_count_gt_diff_le_one hMcard hNcard hcount /-- Convert the lower-threshold succ-degree root-count formulation into the @@ -236,8 +240,9 @@ theorem succDegreeRootCountAbove_of_rootCount ∀ x : ℝ, ((f.roots.filter (x < ·)).card : ℤ) - (g.roots.filter (x < ·)).card ≤ 1 ∧ ((g.roots.filter (x < ·)).card : ℤ) - (f.roots.filter (x < ·)).card ≤ 1 := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree + 1 := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree + 1 := by + rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact count_gt_diff_le_one_of_count_le_two hMcard hNcard hcount /-- If every entry of a list lies strictly above `x`, then filtering by diff --git a/RealRooted/CommonInterleaver/RootDesc.lean b/RealRooted/CommonInterleaver/RootDesc.lean index 0b45a22bc..f72361d76 100644 --- a/RealRooted/CommonInterleaver/RootDesc.lean +++ b/RealRooted/CommonInterleaver/RootDesc.lean @@ -47,7 +47,7 @@ def rootSeqDesc (f : ℝ[X]) : List ℝ := @[simp] lemma rootSeqDesc_length {f : ℝ[X]} (hf : f.Splits) : (rootSeqDesc f).length = f.natDegree := by - simp [rootSeqDesc, card_roots_of_splits hf] + simp [rootSeqDesc, Polynomial.splits_iff_card_roots.mp hf] @[simp] lemma rootSeqDesc_eq_nil {f : ℝ[X]} (hf : f.Splits) : rootSeqDesc f = [] ↔ f.natDegree = 0 := by simp [← List.length_eq_zero_iff, hf] @@ -194,9 +194,9 @@ theorem strictInterl_iff_rootSeqDesc {f g : ℝ[X]} : constructor · rintro ⟨hf, hg, ss, rs, hss_p, hrs_p, hss_eq, hrs_eq, hshape⟩ have hssL : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrsL : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have hSf : rootSeqDesc f = ss.reverse := rootSeqDesc_eq_reverse_of_pairwise hss_p hss_eq have hSg : rootSeqDesc g = rs.reverse := rootSeqDesc_eq_reverse_of_pairwise hrs_p hrs_eq obtain ⟨d1, d2⟩ := desc_bounds_of_interlacing_shape ss rs hshape @@ -214,9 +214,9 @@ theorem strictInterl_iff_rootSeqDesc {f g : ℝ[X]} : have hSf : rootSeqDesc f = (f.roots.sort (· ≤ ·)).reverse := rfl have hSg : rootSeqDesc g = (g.roots.sort (· ≤ ·)).reverse := rfl have hssL : (f.roots.sort (· ≤ ·)).length = f.natDegree := by - rw [Multiset.length_sort, card_roots_of_splits hf.2] + rw [Multiset.length_sort, Polynomial.splits_iff_card_roots.mp hf.2] have hrsL : (g.roots.sort (· ≤ ·)).length = g.natDegree := by - rw [Multiset.length_sort, card_roots_of_splits hg.2] + rw [Multiset.length_sort, Polynomial.splits_iff_card_roots.mp hg.2] refine ⟨hf, hg, f.roots.sort (· ≤ ·), g.roots.sort (· ≤ ·), Multiset.pairwise_sort .., Multiset.pairwise_sort .., Multiset.sort_eq .., Multiset.sort_eq .., ?_⟩ diff --git a/RealRooted/CommonInterleaver/RootSelection.lean b/RealRooted/CommonInterleaver/RootSelection.lean index 87255dfd9..c5c93e9f0 100644 --- a/RealRooted/CommonInterleaver/RootSelection.lean +++ b/RealRooted/CommonInterleaver/RootSelection.lean @@ -42,9 +42,9 @@ theorem StrictInterl.eval_neg_of_left_top_gap {h p : ℝ[X]} {x : ℝ} p.eval x < 0 := by obtain ⟨hh, hp, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, hshape⟩ := hhp have hss_length : ss.length = h.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hh.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hh.2] have hrs_length : rs.length = p.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hp.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hp.2] rcases hshape with ⟨hlen, hinter⟩ | ⟨hlen, _⟩ · have hrs_ne : rs ≠ [] := by intro hrs_nil @@ -71,7 +71,7 @@ theorem StrictInterl.eval_neg_of_left_top_gap {h p : ℝ[X]} {x : ℝ} exact sub_pos.mpr (hdrop_lt z hz) calc p.eval x = p.leadingCoeff * (rs.map (x - ·)).prod := by - rw [eval_eq_leadingCoeff_mul_prod_sub hp.2 x, ← hrs_eq] + rw [Polynomial.Splits.eval_eq_prod_roots hp.2 x, ← hrs_eq] rfl _ = p.leadingCoeff * ((rs.dropLast.map (x - ·)).prod * (x - rs.getLast hrs_ne)) := by diff --git a/RealRooted/CommonInterleaver/RootSlots.lean b/RealRooted/CommonInterleaver/RootSlots.lean index 4b77b927a..1d9696de4 100644 --- a/RealRooted/CommonInterleaver/RootSlots.lean +++ b/RealRooted/CommonInterleaver/RootSlots.lean @@ -131,7 +131,8 @@ protected lemma CommonInterleaver.RootSlots.mem_rootSlotInterval_of_strictInterl {f g : ℝ[X]} (hfg : StrictInterl f g) (j : Fin g.natDegree) : (rootSeqDesc g).get ⟨j.1, by rcases hfg with ⟨_, hg, _, _, _, _, _, _, _⟩ - simp [rootSeqDesc, card_roots_of_splits hg.2]⟩ ∈ rootSlotInterval (rootSeqDesc f) + simp [rootSeqDesc, Polynomial.splits_iff_card_roots.mp hg.2]⟩ ∈ + rootSlotInterval (rootSeqDesc f) ⟨j.1, by have hdeg := hfg.natDegree_le_succ rcases hfg with ⟨hf, hg, _, _, _, _, _, _, _⟩ @@ -141,11 +142,11 @@ protected lemma CommonInterleaver.RootSlots.mem_rootSlotInterval_of_strictInterl have hss_desc : rootSeqDesc f = ss.reverse := rootSeqDesc_eq_reverse_of_pairwise hss hss_eq have hrs_desc : rootSeqDesc g = rs.reverse := rootSeqDesc_eq_reverse_of_pairwise hrs hrs_eq have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] let jg_desc : Fin (rootSeqDesc g).length := ⟨j.1, by - simp [rootSeqDesc, card_roots_of_splits hg.2]⟩ + simp [rootSeqDesc, Polynomial.splits_iff_card_roots.mp hg.2]⟩ let jg_rev : Fin rs.reverse.length := ⟨j.1, by simp [List.length_reverse, hrs_len]⟩ let jf_desc : Fin ((rootSeqDesc f).length + 1) := ⟨j.1, by @@ -201,7 +202,7 @@ protected lemma CommonInterleaver.RootSlots.mem_shifted_rootSlotInterval_of_stri {h f : ℝ[X]} (hhf : StrictInterl h f) (j : Fin h.natDegree) : (rootSeqDesc h).get ⟨j.1, by rcases hhf with ⟨hh, _, _, _, _, _, _, _, _⟩ - simp [rootSeqDesc, card_roots_of_splits hh.2]⟩ ∈ + simp [rootSeqDesc, Polynomial.splits_iff_card_roots.mp hh.2]⟩ ∈ rootSlotInterval (rootSeqDesc f) ⟨j.1 + 1, by have hdeg := hhf.natDegree_le @@ -212,11 +213,11 @@ protected lemma CommonInterleaver.RootSlots.mem_shifted_rootSlotInterval_of_stri have hss_desc : rootSeqDesc h = ss.reverse := rootSeqDesc_eq_reverse_of_pairwise hss hss_eq have hrs_desc : rootSeqDesc f = rs.reverse := rootSeqDesc_eq_reverse_of_pairwise hrs hrs_eq have hss_len : ss.length = h.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hh.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hh.2] have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] let jh_desc : Fin (rootSeqDesc h).length := ⟨j.1, by - simp [rootSeqDesc, card_roots_of_splits hh.2]⟩ + simp [rootSeqDesc, Polynomial.splits_iff_card_roots.mp hh.2]⟩ let jh_rev : Fin ss.reverse.length := ⟨j.1, by simp [List.length_reverse, hss_len]⟩ let jf_desc : Fin ((rootSeqDesc f).length + 1) := ⟨j.1 + 1, by diff --git a/RealRooted/CommonInterleaver/SameDegreeRootCount.lean b/RealRooted/CommonInterleaver/SameDegreeRootCount.lean index deada94df..4bc47f39c 100644 --- a/RealRooted/CommonInterleaver/SameDegreeRootCount.lean +++ b/RealRooted/CommonInterleaver/SameDegreeRootCount.lean @@ -144,8 +144,8 @@ theorem rootCrossing_of_rootCountAbove_diff_le_one (rootSeqDesc g).getD j 0 ≤ (rootSeqDesc f).getD (j - 1) 0) ∧ (∀ j, 1 ≤ j → j < f.natDegree → (rootSeqDesc f).getD j 0 ≤ (rootSeqDesc g).getD (j - 1) 0) := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree := by rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact rootCrossing_of_count_gt_diff_le_one hMcard hNcard hcount /-- Same-degree descending-root crossing implies the lower-threshold root-count @@ -161,8 +161,8 @@ theorem sameDegreeRootCount_of_rootCrossing ∀ x : ℝ, ((f.roots.filter (· ≤ x)).card : ℤ) - (g.roots.filter (· ≤ x)).card ≤ 1 ∧ ((g.roots.filter (· ≤ x)).card : ℤ) - (f.roots.filter (· ≤ x)).card ≤ 1 := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree := by rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] simpa [rootSeqDesc] using (count_diff_le_one_of_rootCrossing (M := f.roots) (N := g.roots) hMcard hNcard hcross) @@ -178,8 +178,8 @@ theorem sameDegreeRootCountAbove_of_rootCount ∀ x : ℝ, ((f.roots.filter (x < ·)).card : ℤ) - (g.roots.filter (x < ·)).card ≤ 1 ∧ ((g.roots.filter (x < ·)).card : ℤ) - (f.roots.filter (x < ·)).card ≤ 1 := by - have hMcard : f.roots.card = f.natDegree := card_roots_of_splits hf - have hNcard : g.roots.card = f.natDegree := by rw [card_roots_of_splits hg, hdeg] + have hMcard : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hf + have hNcard : g.roots.card = f.natDegree := by rw [Polynomial.splits_iff_card_roots.mp hg, hdeg] exact count_gt_diff_le_one_of_count_le_diff_le_one hMcard hNcard hcount /-- Low-degree base case for the same-degree root-count formulation. @@ -195,13 +195,13 @@ theorem rootCount_diff_le_one_of_natDegree_le_one calc (f.roots.filter (· ≤ x)).card ≤ f.roots.card := Multiset.card_le_card (Multiset.filter_le _ _) - _ = f.natDegree := card_roots_of_splits hf + _ = f.natDegree := Polynomial.splits_iff_card_roots.mp hf _ ≤ 1 := hfdeg have hgcard_nat : (g.roots.filter (· ≤ x)).card ≤ 1 := by calc (g.roots.filter (· ≤ x)).card ≤ g.roots.card := Multiset.card_le_card (Multiset.filter_le _ _) - _ = g.natDegree := card_roots_of_splits hg + _ = g.natDegree := Polynomial.splits_iff_card_roots.mp hg _ = f.natDegree := hdeg _ ≤ 1 := hfdeg have hfcard : ((f.roots.filter (· ≤ x)).card : ℤ) ≤ 1 := by exact_mod_cast hfcard_nat diff --git a/RealRooted/CommonInterleaver/SuccDegreeLowDegree.lean b/RealRooted/CommonInterleaver/SuccDegreeLowDegree.lean index b18bf1275..b5142e918 100644 --- a/RealRooted/CommonInterleaver/SuccDegreeLowDegree.lean +++ b/RealRooted/CommonInterleaver/SuccDegreeLowDegree.lean @@ -209,14 +209,14 @@ theorem succDegreeRootCount_of_natDegree_eq_zero calc (f.roots.filter (· ≤ x)).card ≤ f.roots.card := Multiset.card_le_card (Multiset.filter_le _ _) - _ = f.natDegree := card_roots_of_splits hf + _ = f.natDegree := Polynomial.splits_iff_card_roots.mp hf _ = 0 := hfdeg exact Nat.eq_zero_of_le_zero hle have hgcard_nat : (g.roots.filter (· ≤ x)).card ≤ 1 := by calc (g.roots.filter (· ≤ x)).card ≤ g.roots.card := Multiset.card_le_card (Multiset.filter_le _ _) - _ = g.natDegree := card_roots_of_splits hg + _ = g.natDegree := Polynomial.splits_iff_card_roots.mp hg _ = f.natDegree + 1 := hdeg _ = 1 := by rw [hfdeg] have hfcard : ((f.roots.filter (· ≤ x)).card : ℤ) = 0 := by exact_mod_cast hfcard_nat @@ -256,7 +256,7 @@ private lemma exists_linear_factor_of_natDegree_one (hfdeg : f.natDegree = 1) : ∃ a α : ℝ, 0 < a ∧ f.roots = {α} ∧ f = C a * (X - C α) := by obtain ⟨α, hα⟩ : ∃ α, f.roots = {α} := - Multiset.card_eq_one.mp (by rw [card_roots_of_splits hf_split, hfdeg]) + Multiset.card_eq_one.mp (by rw [Polynomial.splits_iff_card_roots.mp hf_split, hfdeg]) refine ⟨f.leadingCoeff, α, hf_pos, hα, ?_⟩ have hprod := hf_split.eq_prod_roots rw [hα] at hprod @@ -270,7 +270,7 @@ private lemma exists_quadratic_factor_of_natDegree_two ∃ b β γ : ℝ, 0 < b ∧ γ ≤ β ∧ g.roots = {β, γ} ∧ g = C b * ((X - C β) * (X - C γ)) := by obtain ⟨r, s, hrs⟩ : ∃ r s, g.roots = {r, s} := - Multiset.card_eq_two.mp (by rw [card_roots_of_splits hg_split, hgdeg]) + Multiset.card_eq_two.mp (by rw [Polynomial.splits_iff_card_roots.mp hg_split, hgdeg]) have hprod := hg_split.eq_prod_roots rcases le_total s r with hle | hle · refine ⟨g.leadingCoeff, r, s, hg_pos, hle, hrs, ?_⟩ diff --git a/RealRooted/CommonInterleaverExamples.lean b/RealRooted/CommonInterleaverExamples.lean index e2694da9c..889a0948b 100644 --- a/RealRooted/CommonInterleaverExamples.lean +++ b/RealRooted/CommonInterleaverExamples.lean @@ -39,11 +39,11 @@ private lemma threeMul_xAddOne_hasPosLeadingCoeff : private lemma twoMul_xAddOne_hasNonnegCoeffs : HasNonnegCoeffs (C (2 : ℝ) * (X + 1)) := - nonnegCoeffs_C_mul (by simp) hasNonnegCoeffs_X_add_one + hasNonnegCoeffs_C_mul (by simp) hasNonnegCoeffs_X_add_one private lemma threeMul_xAddOne_hasNonnegCoeffs : HasNonnegCoeffs (C (3 : ℝ) * (X + 1)) := - nonnegCoeffs_C_mul (by simp) hasNonnegCoeffs_X_add_one + hasNonnegCoeffs_C_mul (by simp) hasNonnegCoeffs_X_add_one lemma scaledLinearFamily_isRealRooted : ∀ f ∈ scaledLinearFamily, (f ≠ 0 ∧ f.Splits) := by diff --git a/RealRooted/Compatibility/Affine.lean b/RealRooted/Compatibility/Affine.lean index fc24b11ac..a3123b573 100644 --- a/RealRooted/Compatibility/Affine.lean +++ b/RealRooted/Compatibility/Affine.lean @@ -36,10 +36,10 @@ theorem compatible_X_mul_affine_affine_of_cross have hstrictInterl : StrictInterl (C u * X + C v) (C U * X + C V) := strictInterl_affine_linear_affine_linear_of_cross hu hU hcross have hnn_left : HasNonnegCoeffs (C u * X + C v) := - (nonnegCoeffs_C_mul hu.le hasNonnegCoeffs_X).add + (hasNonnegCoeffs_C_mul hu.le hasNonnegCoeffs_X).add (hasNonnegCoeffs_C hv) have hnn_right : HasNonnegCoeffs (C U * X + C V) := - (nonnegCoeffs_C_mul hU.le hasNonnegCoeffs_X).add + (hasNonnegCoeffs_C_mul hU.le hasNonnegCoeffs_X).add (hasNonnegCoeffs_C hV) exact (Compatible.of_strictInterl <| diff --git a/RealRooted/Compatibility/Basic.lean b/RealRooted/Compatibility/Basic.lean index d8b591541..caaf5f74e 100644 --- a/RealRooted/Compatibility/Basic.lean +++ b/RealRooted/Compatibility/Basic.lean @@ -119,7 +119,7 @@ lemma reflect_of_natDegree_le {f g : ℝ[X]} (h : Compatible f g) {N : ℕ} · right rw [hcomb] exact ⟨fun hzero => hrr.1 (Polynomial.reflect_eq_zero_iff.mp hzero), - DegreeDropReversal.splits_reflect_of_splits hrr.2 hdeg_combo⟩ + Polynomial.Splits.reflect hrr.2 hdeg_combo⟩ /-- Reflecting both members at a common degree bound preserves and reflects compatibility. -/ diff --git a/RealRooted/Compatibility/CutTransformObstruction.lean b/RealRooted/Compatibility/CutTransformObstruction.lean index 845ff9b48..87bb870f7 100644 --- a/RealRooted/Compatibility/CutTransformObstruction.lean +++ b/RealRooted/Compatibility/CutTransformObstruction.lean @@ -36,11 +36,11 @@ private theorem qConst_nonneg (i : Fin 2) : 0 ≤ qConst i := by fin_cases i <;> norm_num [qConst] private theorem P_nonneg (i : Fin 2) : HasNonnegCoeffs (P i) := - (nonnegCoeffs_C_mul zero_le_one hasNonnegCoeffs_X).add + (hasNonnegCoeffs_C_mul zero_le_one hasNonnegCoeffs_X).add (hasNonnegCoeffs_C (pConst_nonneg i)) private theorem Q_nonneg (i : Fin 2) : HasNonnegCoeffs (Q i) := - (nonnegCoeffs_C_mul zero_le_one hasNonnegCoeffs_X).add + (hasNonnegCoeffs_C_mul zero_le_one hasNonnegCoeffs_X).add (hasNonnegCoeffs_C (qConst_nonneg i)) private theorem P_pos (i : Fin 2) : HasPosLeadingCoeff (P i) := by diff --git a/RealRooted/Compatibility/LeanderOutput.lean b/RealRooted/Compatibility/LeanderOutput.lean index 4899ca2c1..a2f8377c3 100644 --- a/RealRooted/Compatibility/LeanderOutput.lean +++ b/RealRooted/Compatibility/LeanderOutput.lean @@ -15,7 +15,7 @@ theorem leanderAffineFactor_hasNonnegCoeffs {a b : ℝ} (ha : 0 ≤ a) (hb : 0 ≤ b) : HasNonnegCoeffs (leanderAffineFactor a b) := (hasNonnegCoeffs_C ha).add - (nonnegCoeffs_C_mul hb hasNonnegCoeffs_X) + (hasNonnegCoeffs_C_mul hb hasNonnegCoeffs_X) theorem leanderAffineFactor_eq_zero_iff (a b : ℝ) : leanderAffineFactor a b = 0 ↔ a = 0 ∧ b = 0 := by diff --git a/RealRooted/Compatibility/Pair.lean b/RealRooted/Compatibility/Pair.lean index 0d7d3ff52..07b7ba9a4 100644 --- a/RealRooted/Compatibility/Pair.lean +++ b/RealRooted/Compatibility/Pair.lean @@ -105,7 +105,7 @@ theorem map_linearMap_of_nonneg let p := C α * f + C β * g have hp : HasNonnegCoeffs p := by dsimp [p] - exact (nonnegCoeffs_C_mul hα hf).add (nonnegCoeffs_C_mul hβ hg) + exact (hasNonnegCoeffs_C_mul hα hf).add (hasNonnegCoeffs_C_mul hβ hg) have hpdeg : p.natDegree ≤ d := (natDegree_add_le _ _).trans <| max_le ((natDegree_C_mul_le α f).trans hfdeg) diff --git a/RealRooted/DegreeDropDivXPrec.lean b/RealRooted/DegreeDropDivXPrec.lean index 93f12bf44..8644935a5 100644 --- a/RealRooted/DegreeDropDivXPrec.lean +++ b/RealRooted/DegreeDropDivXPrec.lean @@ -41,7 +41,7 @@ lemma card_divX_roots_succ_eq_natDegree_of_coeff_zero {g : ℝ[X]} (hg : g ≠ 0) (hg0 : g.coeff 0 = 0) (hgs : g.Splits) : Multiset.card g.divX.roots + 1 = g.natDegree := by rw [card_divX_roots_succ_eq_card_roots_of_coeff_zero hg hg0, - card_roots_of_splits hgs] + Polynomial.splits_iff_card_roots.mp hgs] /-- Succ-degree form of `card_divX_roots_succ_eq_natDegree_of_coeff_zero`, keyed to the lower-degree endpoint. -/ @@ -260,9 +260,9 @@ theorem strictInterl_divX_left_of_strictInterl_sameDegree_of_roots_nonpos_coeff_ obtain ⟨hf, hg, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, hshape⟩ := hstrictInterl have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have hAlt : ListAlternates ss rs := by rcases hshape with ⟨hlen, _⟩ | ⟨_, halt⟩ · lia @@ -334,9 +334,9 @@ theorem strictInterl_divX_left_of_strictInterl_of_hasNonnegCoeffs_coeff_zero StrictInterl (g.divX) f := by obtain ⟨hf, hg, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, hshape⟩ := hstrictInterl have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have hlen1 : ss.length + 1 = rs.length := by simp_all have hInter : ListInterlaces ss rs := by simp_all have hrs_ne : rs ≠ [] := by grind @@ -396,9 +396,9 @@ theorem strictInterl_of_strictInterl_divX_left_of_hasNonnegCoeffs_coeff_zero obtain ⟨hdivX, hf, aa, bb, haa_sorted, hbb_sorted, haa_eq, hbb_eq, hshape⟩ := hstrictInterl have haa_len : aa.length = g.divX.natDegree := by - rw [← Multiset.coe_card, haa_eq, card_roots_of_splits hdivX.2] + rw [← Multiset.coe_card, haa_eq, Polynomial.splits_iff_card_roots.mp hdivX.2] have hbb_len : bb.length = f.natDegree := by - rw [← Multiset.coe_card, hbb_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hbb_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hdivX_deg : g.divX.natDegree = f.natDegree := natDegree_divX_eq_of_succDegree hdeg have hAlt : ListAlternates aa bb := by simp_all diff --git a/RealRooted/DegreeDropReversal.lean b/RealRooted/DegreeDropReversal.lean index 87dc8875b..f1290bfe6 100644 --- a/RealRooted/DegreeDropReversal.lean +++ b/RealRooted/DegreeDropReversal.lean @@ -18,14 +18,6 @@ namespace RealRooted.DegreeDropReversal variable {K : Type*} [Field K] -/-- Reversal sends a monic linear factor `X + C a` to a polynomial that still -splits. -/ -theorem splits_reverse_X_add_C (a : K) : - (X + C a).reverse.Splits := - Polynomial.Splits.of_natDegree_le_one <| - (Polynomial.reverse_natDegree_le (X + C a)).trans <| by - simp - /-- Predicate root-count transport across `reverse`: filtering roots of the reverse by `q` counts exactly the original roots whose inverse satisfies `q`. -/ theorem card_filter_reverse_roots {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) @@ -54,18 +46,10 @@ theorem mem_roots_reverse_iff {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) rw [Polynomial.roots_reverse_eq_map_inv hp h0, Multiset.mem_map] /-- Reversal preserves `Splits` over a field. -/ +@[deprecated Polynomial.Splits.reverse (since := "2026-10-21")] theorem splits_reverse {p : K[X]} (h : p.Splits) : - p.reverse.Splits := by - induction h using Submonoid.closure_induction with - | mem x hx => - rcases hx with ⟨a, rfl⟩ | ⟨a, rfl⟩ - · simp - · exact splits_reverse_X_add_C a - | one => - exact Polynomial.Splits.of_natDegree_le_one <| - (Polynomial.reverse_natDegree_le (1 : K[X])).trans <| by simp - | mul x y _ _ ihx ihy => - simp_all + p.reverse.Splits := + h.reverse /-- Reflecting a polynomial at a degree `N` at least its own `natDegree` factors a power of `X` out of its reversal. -/ @@ -102,27 +86,19 @@ theorem leadingCoeff_reflect_eq_coeff_zero_of_natDegree_le {R : Type*} [Semiring (reflect N p).leadingCoeff = p.coeff 0 := by simp [Polynomial.leadingCoeff, natDegree_reflect_eq_of_coeff_zero_ne hN h0] -/-- Multiplying the reverse of a split polynomial by the degree-padding power -of `X` still splits. -/ -theorem splits_X_pow_mul_reverse {p : K[X]} (h : p.Splits) (N : ℕ) : - (X ^ (N - p.natDegree) * p.reverse).Splits := - (Polynomial.Splits.X_pow (N - p.natDegree)).mul (splits_reverse h) - /-- Reflection at any degree at least `p.natDegree` preserves splitting. -/ +@[deprecated Polynomial.Splits.reflect (since := "2026-10-21")] theorem splits_reflect_of_splits {p : K[X]} (h : p.Splits) {N : ℕ} (hN : p.natDegree ≤ N) : - (reflect N p).Splits := by - simpa [reflect_eq_X_pow_mul_reverse p hN] using - splits_X_pow_mul_reverse h N + (reflect N p).Splits := + h.reflect hN /-- For polynomials of degree at most `N`, reflection preserves and reflects splitting. -/ +@[deprecated Polynomial.splits_reflect_iff (since := "2026-10-21")] theorem splits_reflect_iff {p : K[X]} {N : ℕ} (hN : p.natDegree ≤ N) : - (reflect N p).Splits ↔ p.Splits := by - refine ⟨?_, fun h ↦ splits_reflect_of_splits h hN⟩ - intro h - simpa using splits_reflect_of_splits h <| - (Polynomial.natDegree_reflect_le (N := N) (p := p)).trans (max_eq_left hN).le + (reflect N p).Splits ↔ p.Splits := + Polynomial.splits_reflect_iff hN /-- Reflection sends a nonzero root to its inverse at any valid degree bound. -/ theorem isRoot_reflect_inv_iff {p : K[X]} {b : K} (hb : b ≠ 0) @@ -133,17 +109,6 @@ theorem isRoot_reflect_inv_iff {p : K[X]} {b : K} (hb : b ≠ 0) simpa [Polynomial.eval₂_id, invOf_eq_inv] using (Polynomial.eval₂_reflect_eq_zero_iff (RingHom.id K) b N p hN) -/-- Reversal preserves and reflects splitting over a field. -/ -theorem splits_reverse_iff {p : K[X]} : - p.reverse.Splits ↔ p.Splits := by - simpa [Polynomial.reverse] using - (splits_reflect_iff (p := p) (N := p.natDegree) le_rfl) - -/-- If the reverse of a polynomial splits, then the original polynomial splits. -/ -theorem splits_of_reverse {p : K[X]} (h : p.reverse.Splits) : - p.Splits := - splits_reverse_iff.mp h - /-- Multiplying by a power of `X` does not change whether a polynomial splits. -/ theorem splits_X_pow_mul_iff {p : K[X]} (k : ℕ) : (X ^ k * p).Splits ↔ p.Splits := by @@ -180,7 +145,7 @@ section Ordered variable [LinearOrder K] [IsStrictOrderedRing K] /-- Inversion sends the positive half-line `(a, ∞)` to `(0, a⁻¹)`. -/ -theorem mem_Ioi_inv_iff {a r : K} (ha : 0 < a) : +private theorem mem_Ioi_inv_iff {a r : K} (ha : 0 < a) : a < r⁻¹ ↔ (0 < r ∧ r < a⁻¹) := by by_cases hr : 0 < r · constructor <;> intro h <;> simp_all [lt_inv_comm₀] @@ -190,7 +155,7 @@ theorem mem_Ioi_inv_iff {a r : K} (ha : 0 < a) : inv_pos.2 ha] /-- Half-line root-count transport under reversal. -/ -theorem card_roots_reverse_Ioi {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) +private theorem card_roots_reverse_Ioi {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) {a : K} (ha : 0 < a) : (p.reverse.roots.filter (fun x => a < x)).card = (p.roots.filter (fun r => 0 < r ∧ r < a⁻¹)).card := by @@ -217,13 +182,13 @@ theorem card_roots_reflect_Ioi {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) Multiset.card_zero, zero_add] /-- On the negative half-line, inversion reverses a strict-upper comparison. -/ -theorem mem_Ioi_inv_iff_of_neg {a r : K} (ha : a < 0) (hr : r < 0) : +private theorem mem_Ioi_inv_iff_of_neg {a r : K} (ha : a < 0) (hr : r < 0) : a < r⁻¹ ↔ r < a⁻¹ := by simpa using inv_lt_inv_of_neg (inv_lt_zero'.2 ha) hr /-- Strict-upper root-count transport under reversal at a negative threshold, assuming all original roots are strictly negative. -/ -theorem card_roots_reverse_Ioi_of_neg {p : K[X]} (hp : p.Splits) +private theorem card_roots_reverse_Ioi_of_neg {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) {a : K} (ha : a < 0) (hneg : ∀ r ∈ p.roots, r < 0) : (p.reverse.roots.filter (fun x => a < x)).card = @@ -235,7 +200,7 @@ theorem card_roots_reverse_Ioi_of_neg {p : K[X]} (hp : p.Splits) /-- At a negative threshold, the reflected strict-upper count consists of all degree-padding zeros together with the original roots lying below the inverse threshold. -/ -theorem card_roots_reflect_Ioi_of_neg {p : K[X]} (hp : p.Splits) +private theorem card_roots_reflect_Ioi_of_neg {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) {N : ℕ} (hN : p.natDegree ≤ N) {a : K} (ha : a < 0) (hneg : ∀ r ∈ p.roots, r < 0) : ((reflect N p).roots.filter (fun x => a < x)).card = diff --git a/RealRooted/Derivative/FamilyClosure.lean b/RealRooted/Derivative/FamilyClosure.lean index 043e72688..f2e5112d0 100644 --- a/RealRooted/Derivative/FamilyClosure.lean +++ b/RealRooted/Derivative/FamilyClosure.lean @@ -15,6 +15,7 @@ noncomputable section namespace RealRooted /-- Splitting is preserved by differentiation in the zero-aware convention. -/ +@[deprecated Polynomial.Splits.derivative +typeChanged (since := "2026-10-21")] theorem eq_zero_or_splits_derivative {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) : p.derivative = 0 ∨ p.derivative.Splits := by @@ -23,6 +24,7 @@ theorem eq_zero_or_splits_derivative {p : ℝ[X]} · exact Or.inr hp.derivative /-- Iterating the zero-aware derivative closure preserves splitting. -/ +@[deprecated Polynomial.Splits.iterate_derivative +typeChanged (since := "2026-10-21")] theorem iterate_derivative_eq_zero_or_splits {p : ℝ[X]} (hsplit : p.Splits) (n : ℕ) : (derivative^[n]) p = 0 ∨ ((derivative^[n]) p).Splits := diff --git a/RealRooted/Derivative/Interlacing.lean b/RealRooted/Derivative/Interlacing.lean index 83d77137f..96a235a38 100644 --- a/RealRooted/Derivative/Interlacing.lean +++ b/RealRooted/Derivative/Interlacing.lean @@ -28,7 +28,7 @@ noncomputable def mkInterleaving (f : ℝ[X]) : else r₁ s :: mkInterleaving f (r₂ :: rest) hrest -lemma mkInterleaving_length (f : ℝ[X]) : +private lemma mkInterleaving_length (f : ℝ[X]) : ∀ (rs : List ℝ) (hrs : ∀ r ∈ rs, f.IsRoot r), (mkInterleaving f rs hrs).length = rs.length - 1 | [], _ | [_], _ => by simp [mkInterleaving] @@ -42,7 +42,7 @@ so that the induction goes through when we drop the first element. -/ /-- Each constructed element is a root of f' in [r₁, r₂]. Uses sub-multiset condition `≤` to handle repeated roots. -/ -lemma mkInterleaving_spec (f : ℝ[X]) : +private lemma mkInterleaving_spec (f : ℝ[X]) : ∀ (rs : List ℝ) (hrs : ∀ r ∈ rs, f.IsRoot r) (_ : rs.Pairwise (· ≤ ·)) (_ : (↑rs : Multiset ℝ) ≤ f.roots), @@ -78,28 +78,6 @@ lemma mkInterleaving_spec (f : ℝ[X]) : · grind · grind -/-! ## Sortedness from interleaving -/ - -/-- If `ss` interleaves with sorted `rs`, then `ss` is sorted. -/ -lemma sorted_of_listInterlaces : - ∀ (ss rs : List ℝ), - rs.Pairwise (· ≤ ·) → - ListInterlaces ss rs → - ss.Pairwise (· ≤ ·) - | [], _, _, _ => List.Pairwise.nil - | [_], _, _, _ => List.pairwise_singleton _ _ - | s₁ :: s₂ :: ss', r₁ :: r₂ :: r₃ :: rs', hrs, hint => by - obtain ⟨_, hs₁r₂, hint_tail⟩ := hint - have hr₂s₂ : r₂ ≤ s₂ := hint_tail.1 - have hrs_tail : (r₂ :: r₃ :: rs').Pairwise (· ≤ ·) := - (List.pairwise_cons.mp hrs).2 - have ih := sorted_of_listInterlaces (s₂ :: ss') (r₂ :: r₃ :: rs') hrs_tail hint_tail - grind - | _ :: _ :: _, _ :: _ :: [], _, hint => by - simp [ListInterlaces] at hint - | _ :: _ :: _, _ :: [], _, hint => by simp [ListInterlaces] at hint - | _ :: _ :: _, [], _, hint => by simp [ListInterlaces] at hint - /-! ## Sub-multiset relation -/ /-- All elements of the interleaving of `r₁ :: rest` are ≥ r₁. -/ @@ -123,7 +101,7 @@ private lemma mkInterleaving_ge (f : ℝ[X]) : exact le_trans hr₁r₂ (mkInterleaving_ge f r₂ rest' hrest hsorted_tail hsub_tail x hx) /-- The sub-multiset relation: `↑ss ≤ f'.roots`. -/ -lemma mkInterleaving_sub_multiset (f : ℝ[X]) +private lemma mkInterleaving_sub_multiset (f : ℝ[X]) (hdeg : 2 ≤ f.natDegree) : ∀ (rs : List ℝ) (hrs : ∀ r ∈ rs, f.IsRoot r) (_ : rs.Pairwise (· ≤ ·)) @@ -267,9 +245,9 @@ lemma StrictInterl.of_degree_zero_right_of_degree_one (hf_deg0 : f.natDegree = 0) (hg_deg1 : g.natDegree = 1) : StrictInterl f g := by obtain ⟨r, hr_eq⟩ := Multiset.card_eq_one.mp (by - simpa [hg_deg1] using card_roots_of_splits hg_splits) + simpa [hg_deg1] using Polynomial.splits_iff_card_roots.mp hg_splits) have hroots_f : f.roots = 0 := Multiset.card_eq_zero.mp (by - simpa [hf_deg0] using card_roots_of_splits hf_splits) + simpa [hf_deg0] using Polynomial.splits_iff_card_roots.mp hf_splits) refine ⟨⟨hf_ne, hf_splits⟩, ⟨hg_ne, hg_splits⟩, [], [r], by simp, List.pairwise_singleton _ _, ?_, ?_, ?_⟩ · simp [hroots_f] @@ -293,7 +271,7 @@ theorem derivative_interlaces_of_natDegree_ne_zero {f : ℝ[X]} (hf : f.Splits) have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hrs_multiset : (↑rs : Multiset ℝ) = f.roots := Multiset.sort_eq .. have hrs_length : rs.length = f.natDegree := by - rw [hrs_def, Multiset.length_sort, card_roots_of_splits hf] + rw [hrs_def, Multiset.length_sort, Polynomial.splits_iff_card_roots.mp hf] have hrs_root : ∀ r ∈ rs, f.IsRoot r := by simp_all set ss := mkInterleaving f rs hrs_root have hss_length : ss.length = f.natDegree - 1 := by rw [mkInterleaving_length]; lia @@ -314,9 +292,9 @@ theorem derivative_interlaces_of_natDegree_ne_zero {f : ℝ[X]} (hf : f.Splits) (le_of_eq (by rw [hf'_card, f.natDegree_derivative, ← hss_length, ← Multiset.coe_card])) have hss_sorted : ss.Pairwise (· ≤ ·) := - sorted_of_listInterlaces ss rs hrs_sorted hss_interlaces + pairwise_le_of_listInterlaces ss rs hss_interlaces exact ⟨⟨by rintro rfl; simp at hf'_ne, hf⟩, - ⟨hf'_ne, splits_of_card_roots hf'_card⟩, by rw [f.natDegree_derivative]; lia, + ⟨hf'_ne, Polynomial.splits_iff_card_roots.mpr hf'_card⟩, by rw [f.natDegree_derivative]; lia, rs, ss, hrs_sorted, hss_sorted, hrs_multiset, hss_eq, hss_interlaces⟩ /-- Deprecated degree-two form of `derivative_interlaces_of_natDegree_ne_zero`. -/ @@ -338,7 +316,7 @@ theorem exists_derivative_root_eval_nonneg_of_four_le_natDegree ⟨_, hpd, _, rs, ss, _, hss_sorted, hrs_eq, hss_eq, hint⟩ := derivative_interlaces_of_natDegree_ne_zero hp (by lia) have hss_length : ss.length = p.derivative.natDegree := by - rw [← card_roots_of_splits hpd.2, ← hss_eq, Multiset.coe_card] + rw [← Polynomial.splits_iff_card_roots.mp hpd.2, ← hss_eq, Multiset.coe_card] have hss_two : 2 ≤ ss.length := by rw [hss_length, p.natDegree_derivative] lia diff --git a/RealRooted/Derivative/ShiftRootMatching.lean b/RealRooted/Derivative/ShiftRootMatching.lean index 4e1dd725b..4e5b9e6f9 100644 --- a/RealRooted/Derivative/ShiftRootMatching.lean +++ b/RealRooted/Derivative/ShiftRootMatching.lean @@ -49,8 +49,8 @@ theorem exists_delta_roots_rel_tDeriv ((tDeriv eps p).roots.filter (fun q ↦ |q - a| < η)).card := by simpa [tDeriv] using hcount have hcard : (tDeriv eps p).roots.card = p.roots.card := by - rw [card_roots_of_splits (splits_tDeriv heps_pos hp), natDegree_tDeriv, - card_roots_of_splits hp] + rw [Polynomial.splits_iff_card_roots.mp (splits_tDeriv heps_pos hp), natDegree_tDeriv, + Polynomial.splits_iff_card_roots.mp hp] have hrel := Multiset.rel_of_forall_le_count_of_card_eq hsep hcount' hcard exact hrel.mono fun _ _ _ _ hclose ↦ lt_trans hclose hηρ diff --git a/RealRooted/Derivative/SimpleRoots.lean b/RealRooted/Derivative/SimpleRoots.lean index 2b543f850..9895778e3 100644 --- a/RealRooted/Derivative/SimpleRoots.lean +++ b/RealRooted/Derivative/SimpleRoots.lean @@ -87,7 +87,7 @@ theorem roots_derivative_lt_of_roots_le_of_rootMultiplicity_eq_one have hcard : f.derivative.roots.card = 0 := by calc f.derivative.roots.card = f.derivative.natDegree := - card_roots_of_splits hfder_splits + Polynomial.splits_iff_card_roots.mp hfder_splits _ = f.natDegree - 1 := f.natDegree_derivative _ = 0 := by simp [hdeg1] intro r hr diff --git a/RealRooted/DerivativeRecurrence/EndpointWindow.lean b/RealRooted/DerivativeRecurrence/EndpointWindow.lean index 4a90f96e9..434fd0d89 100644 --- a/RealRooted/DerivativeRecurrence/EndpointWindow.lean +++ b/RealRooted/DerivativeRecurrence/EndpointWindow.lean @@ -25,7 +25,7 @@ theorem roots_lt_iff_eval_pos_of_interlaces (hinter : Interlaces f F) (∀ t ∈ F.roots, t < U) ↔ 0 < F.eval U := by constructor · intro hFU - rw [eval_eq_leadingCoeff_mul_prod_sub hinter.1.2 U] + rw [Polynomial.Splits.eval_eq_prod_roots hinter.1.2 U] refine mul_pos hFpos (Multiset.prod_pos fun y hy => ?_) obtain ⟨t, ht, rfl⟩ := Multiset.mem_map.mp hy exact sub_pos.mpr (hFU t ht) @@ -58,7 +58,7 @@ theorem roots_le_iff_eval_nonneg_of_interlaces (hinter : Interlaces f F) (∀ t ∈ F.roots, t ≤ U) ↔ 0 ≤ F.eval U := by constructor · intro hFU - rw [eval_eq_leadingCoeff_mul_prod_sub hinter.1.2 U] + rw [Polynomial.Splits.eval_eq_prod_roots hinter.1.2 U] refine mul_nonneg hFpos.le (Multiset.prod_nonneg fun y hy => ?_) obtain ⟨t, ht, rfl⟩ := Multiset.mem_map.mp hy exact sub_nonneg.mpr (hFU t ht) @@ -91,7 +91,8 @@ theorem roots_gt_iff_neg_one_pow_mul_eval_pos_of_interlaces (hinter : Interlaces (∀ t ∈ F.roots, L < t) ↔ 0 < (-1 : ℝ) ^ F.natDegree * F.eval L := by constructor · intro hFL - rw [eval_eq_leadingCoeff_mul_prod_sub hinter.1.2 L, ← card_roots_of_splits hinter.1.2, + rw [Polynomial.Splits.eval_eq_prod_roots hinter.1.2 L, + ← Polynomial.splits_iff_card_roots.mp hinter.1.2, mul_left_comm, show F.roots.card = (F.roots.map (L - ·)).card by simp, ← Multiset.prod_map_neg] refine mul_pos hFpos (Multiset.prod_pos fun y hy => ?_) @@ -159,7 +160,8 @@ theorem roots_ge_iff_neg_one_pow_mul_eval_nonneg_of_interlaces (hinter : Interla (∀ t ∈ F.roots, L ≤ t) ↔ 0 ≤ (-1 : ℝ) ^ F.natDegree * F.eval L := by constructor · intro hFL - rw [eval_eq_leadingCoeff_mul_prod_sub hinter.1.2 L, ← card_roots_of_splits hinter.1.2, + rw [Polynomial.Splits.eval_eq_prod_roots hinter.1.2 L, + ← Polynomial.splits_iff_card_roots.mp hinter.1.2, mul_left_comm, show F.roots.card = (F.roots.map (L - ·)).card by simp, ← Multiset.prod_map_neg] refine mul_nonneg hFpos.le (Multiset.prod_nonneg fun y hy => ?_) @@ -269,7 +271,7 @@ namespace RealRooted private theorem eval_pos_at_upper_of_roots_lt {p : ℝ[X]} {U : ℝ} (hs : p.Splits) (hpos : 0 < p.leadingCoeff) (h : ∀ t ∈ p.roots, t < U) : 0 < p.eval U := by - rw [eval_eq_leadingCoeff_mul_prod_sub hs U] + rw [Polynomial.Splits.eval_eq_prod_roots hs U] refine mul_pos hpos (Multiset.prod_pos fun y hy => ?_) obtain ⟨t, ht, rfl⟩ := Multiset.mem_map.mp hy linarith [h t ht] @@ -279,7 +281,7 @@ private theorem neg_one_pow_mul_eval_pos_at_lower_of_roots_gt (h : ∀ t ∈ p.roots, L < t) : 0 < (-1 : ℝ) ^ p.natDegree * p.eval L := by have hcard : p.roots.card = (p.roots.map (L - ·)).card := by simp - rw [eval_eq_leadingCoeff_mul_prod_sub hs L, ← card_roots_of_splits hs, + rw [Polynomial.Splits.eval_eq_prod_roots hs L, ← Polynomial.splits_iff_card_roots.mp hs, mul_left_comm, hcard, ← Multiset.prod_map_neg] refine mul_pos hpos (Multiset.prod_pos fun y hy => ?_) obtain ⟨s, hs, rfl⟩ := Multiset.mem_map.mp hy diff --git a/RealRooted/DerivativeRecurrence/Interlacing.lean b/RealRooted/DerivativeRecurrence/Interlacing.lean index 42962ec59..a33ba8ba5 100644 --- a/RealRooted/DerivativeRecurrence/Interlacing.lean +++ b/RealRooted/DerivativeRecurrence/Interlacing.lean @@ -336,10 +336,7 @@ theorem derivProduct_splits {P A : ℕ → ℝ[X]} | zero => exact h0 | succ n ih => rw [hrec] - refine (hA n).mul ?_ - rcases eq_zero_or_splits_derivative (Or.inr ih) with h | h - · simp [h] - · exact h + exact (hA n).mul ih.derivative /-! ## Degrees when the top terms cancel diff --git a/RealRooted/DerivativeRecurrence/RootWindow.lean b/RealRooted/DerivativeRecurrence/RootWindow.lean index 0593f12fa..542126e71 100644 --- a/RealRooted/DerivativeRecurrence/RootWindow.lean +++ b/RealRooted/DerivativeRecurrence/RootWindow.lean @@ -44,8 +44,10 @@ theorem eval_pos_of_roots_le (hs : p.Splits) (hpos : 0 < p.leadingCoeff) theorem neg_one_pow_mul_eval_pos_of_roots_ge (hs : p.Splits) (hpos : 0 < p.leadingCoeff) (h : ∀ t ∈ p.roots, L ≤ t) (hx : x < L) : 0 < (-1) ^ p.natDegree * p.eval x := by - rw [eval_eq_leadingCoeff_mul_prod_sub hs x, ← card_roots_of_splits hs, mul_left_comm, - show p.roots.card = (p.roots.map (x - ·)).card by simp, ← Multiset.prod_map_neg] + rw [Polynomial.Splits.eval_eq_prod_roots hs x, + ← Polynomial.splits_iff_card_roots.mp hs, mul_left_comm, + show p.roots.card = (p.roots.map (x - ·)).card by simp, + ← Multiset.prod_map_neg] refine mul_pos hpos (Multiset.prod_pos fun y hy => ?_) obtain ⟨z, hz, rfl⟩ := Multiset.mem_map.mp hy obtain ⟨t, ht, rfl⟩ := Multiset.mem_map.mp hz @@ -459,11 +461,11 @@ theorem leadingCoeff_mul_sub_mul_eval_le_of_interlaces {f g : ℝ[X]} {U x : ℝ f.leadingCoeff * (x - U) * g.eval x ≤ g.leadingCoeff * f.eval x := by obtain ⟨⟨_, hfs⟩, ⟨_, hgs⟩, hdeg, rs, ss, _, _, hrs, hss, hint⟩ := h have hlen : rs.length = ss.length + 1 := by - rw [← Multiset.coe_card, ← Multiset.coe_card, hrs, hss, card_roots_of_splits hfs, - card_roots_of_splits hgs, hdeg] + rw [← Multiset.coe_card, ← Multiset.coe_card, hrs, hss, Polynomial.splits_iff_card_roots.mp hfs, + Polynomial.splits_iff_card_roots.mp hgs, hdeg] have key := prod_sub_le_of_listInterlaces hx ss rs hlen hint (fun r hr => hU r (by rw [← hrs]; exact Multiset.mem_coe.mpr hr)) - rw [eval_eq_leadingCoeff_mul_prod_sub hgs x, eval_eq_leadingCoeff_mul_prod_sub hfs x, + rw [Polynomial.Splits.eval_eq_prod_roots hgs x, Polynomial.Splits.eval_eq_prod_roots hfs x, ← hrs, ← hss, Multiset.map_coe, Multiset.map_coe, Multiset.prod_coe, Multiset.prod_coe] have hc : 0 ≤ f.leadingCoeff * g.leadingCoeff := (mul_pos hfpos hgpos).le nlinarith [mul_le_mul_of_nonneg_left key hc] @@ -627,7 +629,7 @@ theorem derivative_eval_mul_sub_le_of_roots_le (hs : f.Splits) (hpos : 0 < f.lea have hf := eval_pos_of_roots_le hs hpos hU hx rw [hs.eval_derivative_eq_eval_mul_sum hf.ne'] have hle : (x - U) * (f.roots.map fun z => 1 / (x - z)).sum ≤ f.natDegree := by - rw [← Multiset.sum_map_mul_left, ← card_roots_of_splits hs] + rw [← Multiset.sum_map_mul_left, ← Polynomial.splits_iff_card_roots.mp hs] refine (Multiset.sum_le_card_nsmul _ (1 : ℝ) fun y hy => ?_).trans (by simp) obtain ⟨z, hz, rfl⟩ := Multiset.mem_map.mp hy have := hU z hz @@ -646,7 +648,7 @@ theorem derivative_eval_mul_sub_le_of_roots_ge (hs : f.Splits) (hpos : 0 < f.lea have hne : f.eval x ≠ 0 := fun h => by simp [h] at hf rw [hs.eval_derivative_eq_eval_mul_sum hne] have hle : (x - L) * (f.roots.map fun z => 1 / (x - z)).sum ≤ f.natDegree := by - rw [← Multiset.sum_map_mul_left, ← card_roots_of_splits hs] + rw [← Multiset.sum_map_mul_left, ← Polynomial.splits_iff_card_roots.mp hs] refine (Multiset.sum_le_card_nsmul _ (1 : ℝ) fun y hy => ?_).trans (by simp) obtain ⟨z, hz, rfl⟩ := Multiset.mem_map.mp hy have := hL z hz diff --git a/RealRooted/EulerBidiagonal/ComparisonData.lean b/RealRooted/EulerBidiagonal/ComparisonData.lean index 68aa1d90a..2f6126f48 100644 --- a/RealRooted/EulerBidiagonal/ComparisonData.lean +++ b/RealRooted/EulerBidiagonal/ComparisonData.lean @@ -208,7 +208,7 @@ theorem roots_eq_of_nodup_of_natDegree_le {G : ℝ[X]} {M : Multiset ℝ} (hG : have hcard' : G.roots.card ≤ M.card := (card_roots' G).trans hcard have heq : M = G.roots := Multiset.eq_of_le_of_card_le hle hcard' refine ⟨heq.symm, ?_⟩ - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr apply le_antisymm (card_roots' G) rw [← heq] exact hcard diff --git a/RealRooted/EulerBidiagonal/General.lean b/RealRooted/EulerBidiagonal/General.lean index ab742ef46..4b873a2f0 100644 --- a/RealRooted/EulerBidiagonal/General.lean +++ b/RealRooted/EulerBidiagonal/General.lean @@ -656,7 +656,7 @@ theorem hasSimpleRoots_of_sign_changes_with_left_endpoint have hroots_eq : (↑us : Multiset ℝ) = p.roots := Multiset.eq_of_le_of_card_le hus_sub (by simp only [List.length_ofFn] at hus_len - rw [card_roots_of_splits hsplits, hdegree, Multiset.coe_card, hus_len] + rw [Polynomial.splits_iff_card_roots.mp hsplits, hdegree, Multiset.coe_card, hus_len] lia) apply HasSimpleRoots.of_roots_nodup hp rw [← hroots_eq] @@ -822,7 +822,7 @@ theorem exists_comparison_data have hrs_lt : rs.Pairwise (· < ·) := (hrs_le.and hrs_nodup).imp (fun h => lt_of_le_of_ne h.1 h.2) have hrs_len : rs.length = m := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hqsplits, hqdeg] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hqsplits, hqdeg] have hrs_ne : rs ≠ [] := by intro h rw [h] at hrs_len diff --git a/RealRooted/EulerBidiagonal/GeneralRows.lean b/RealRooted/EulerBidiagonal/GeneralRows.lean index 3716b05eb..fbe6b0941 100644 --- a/RealRooted/EulerBidiagonal/GeneralRows.lean +++ b/RealRooted/EulerBidiagonal/GeneralRows.lean @@ -25,7 +25,7 @@ def generalRows (κ a b u v : ℝ) : ℕ → ℝ[X] theorem strictInterl_one_of_natDegree_eq_one {p : ℝ[X]} (hp : p ≠ 0) (hps : p.Splits) (hdeg : p.natDegree = 1) : StrictInterl (1 : ℝ[X]) p := by have hcard : Multiset.card p.roots = 1 := by - rw [card_roots_of_splits hps, hdeg] + rw [Polynomial.splits_iff_card_roots.mp hps, hdeg] obtain ⟨r, hr⟩ := Multiset.card_eq_one.mp hcard refine ⟨⟨one_ne_zero, Splits.one⟩, ⟨hp, hps⟩, [], [r], by simp, by simp, ?_, ?_, ?_⟩ · simp diff --git a/RealRooted/EulerBidiagonal/Location.lean b/RealRooted/EulerBidiagonal/Location.lean index 8dd7dcc21..a93923e20 100644 --- a/RealRooted/EulerBidiagonal/Location.lean +++ b/RealRooted/EulerBidiagonal/Location.lean @@ -315,7 +315,7 @@ theorem generalComparison_sign_at_generalStep_root_of_one_le have hcnt : q.roots.countP (fun r => e < r) = m := by have : q.roots.countP (fun r => e < r) = Multiset.card q.roots := Multiset.countP_eq_card.mpr (fun r hr => he r hr) - rw [this, card_roots_of_splits hq.2.1, hqdeg] + rw [this, Polynomial.splits_iff_card_roots.mp hq.2.1, hqdeg] rw [hcnt] at h linarith have hLT := generalStep_sign_of_input_sign κ a b u v q e m hprod hqe diff --git a/RealRooted/EulerBidiagonal/PairTheorem.lean b/RealRooted/EulerBidiagonal/PairTheorem.lean index ebb466c21..120788096 100644 --- a/RealRooted/EulerBidiagonal/PairTheorem.lean +++ b/RealRooted/EulerBidiagonal/PairTheorem.lean @@ -29,8 +29,8 @@ theorem isNegativeSimple_divByMonic_X_sub_C {f : ℝ[X]} (hf : IsNegativeSimple have hroots : (f /ₘ (X - C s)).roots = f.roots.erase s := roots_divByMonic_X_sub_C hs have hmem : s ∈ f.roots := (mem_roots hf.1).mpr hs have hsplits : (f /ₘ (X - C s)).Splits := by - apply splits_of_card_roots - rw [hroots, Multiset.card_erase_of_mem hmem, card_roots_of_splits hf.2.1, + apply Polynomial.splits_iff_card_roots.mpr + rw [hroots, Multiset.card_erase_of_mem hmem, Polynomial.splits_iff_card_roots.mp hf.2.1, natDegree_divByMonic_X_sub_C, Nat.pred_eq_sub_one] refine ⟨hne, hsplits, ?_, ?_, ?_⟩ · apply HasSimpleRoots.of_roots_nodup hne @@ -140,7 +140,7 @@ theorem strictInterl_generalStep_add_C_mul_X_mul_of_strictInterl have hd1 : 1 ≤ d := by have hcard : 0 < Multiset.card f.roots := Multiset.card_pos_iff_exists_mem.mpr ⟨s, Multiset.mem_toFinset.mp hs⟩ - rw [card_roots_of_splits hf.2.1, hfd] at hcard + rw [Polynomial.splits_iff_card_roots.mp hf.2.1, hfd] at hcard exact hcard obtain ⟨hBint, hBno⟩ := strictInterl_generalStep_mul_X_sub_C κ a b u v s (f /ₘ (X - C s)) (d - 1) hfs hfsdeg hκ ha hb (fun k hk => hell k (by lia)) hQ diff --git a/RealRooted/EulerOperator.lean b/RealRooted/EulerOperator.lean index c0e0f74a6..0e32eed9d 100644 --- a/RealRooted/EulerOperator.lean +++ b/RealRooted/EulerOperator.lean @@ -248,8 +248,9 @@ theorem exists_isPFPolynomial_not_interl_iterateThetaPlusOne : -- the least root of `q` would lie below the largest root of `p` obtain ⟨-, hright⟩ := (strictInterl_iff_orderedRoot_bounds h.1.1 h.1.2 h.2.1.1 h.2.1.2 hpdeg hqdeg).mp h - have hpr := orderedRoot_mem_roots ((card_roots_of_splits h.1.2).trans hpdeg) ⟨1, by norm_num⟩ - have hqr := orderedRoot_mem_roots ((card_roots_of_splits h.2.1.2).trans hqdeg) 0 + have hpr := orderedRoot_mem_roots + ((Polynomial.splits_iff_card_roots.mp h.1.2).trans hpdeg) ⟨1, by norm_num⟩ + have hqr := orderedRoot_mem_roots ((Polynomial.splits_iff_card_roots.mp h.2.1.2).trans hqdeg) 0 have hle := hright 0 (by norm_num) rw [mem_roots h.1.1, IsRoot.def] at hpr rw [mem_roots h.2.1.1, IsRoot.def] at hqr diff --git a/RealRooted/EulerOperator/Correction.lean b/RealRooted/EulerOperator/Correction.lean index c07afb0a5..06dcd373c 100644 --- a/RealRooted/EulerOperator/Correction.lean +++ b/RealRooted/EulerOperator/Correction.lean @@ -143,8 +143,8 @@ theorem strictInterl_add_derivative_add_thetaPlusOne have hrpos : HasPosLeadingCoeff r := hr.pos_leadingCoeff hrp.1.1 let u := C a * p.derivative + C b * r have hunn : HasNonnegCoeffs u := - (nonnegCoeffs_C_mul ha.le hdernn).add - (nonnegCoeffs_C_mul hb.le hr) + (hasNonnegCoeffs_C_mul ha.le hdernn).add + (hasNonnegCoeffs_C_mul hb.le hr) have hup : StrictInterl u p := by dsimp [u] simpa [weightedSum, weightedSum_cons] using diff --git a/RealRooted/EulerOperator/Pencil.lean b/RealRooted/EulerOperator/Pencil.lean index 88e0d8b96..2f5254e6a 100644 --- a/RealRooted/EulerOperator/Pencil.lean +++ b/RealRooted/EulerOperator/Pencil.lean @@ -38,7 +38,7 @@ theorem strictInterl_thetac_X_mul {f : ℝ[X]} (hf : IsPFPolynomial f) grind have hCf_ne : C c * f ≠ 0 := mul_ne_zero hCc_ne hf0 have hpos_right : HasPosLeadingCoeff (C c * f) := - (nonnegCoeffs_C_mul hc.le hnn).pos_leadingCoeff hCf_ne + (hasNonnegCoeffs_C_mul hc.le hnn).pos_leadingCoeff hCf_ne exact StrictInterl.add_of_right_of_posLeadingCoeff hleft hright hpos_left hpos_right /-- A polynomial-PF `f` precedes every positive Euler pencil of `f` when its @@ -48,7 +48,7 @@ theorem strictInterl_self_thetac {f : ℝ[X]} (hf : IsPFPolynomial f) StrictInterl f (X * f.derivative + C c * f) := by have hnn : HasNonnegCoeffs f := hf.hasNonnegCoeffs have hnn_thc : HasNonnegCoeffs (X * f.derivative + C c * f) := - HasNonnegCoeffs.add hnn.derivative.X_mul (nonnegCoeffs_C_mul hc.le hnn) + HasNonnegCoeffs.add hnn.derivative.X_mul (hasNonnegCoeffs_C_mul hc.le hnn) exact strictInterl_of_strictInterl_X_mul_of_nonneg (strictInterl_thetac_X_mul hf hdeg hc) hnn hnn_thc @@ -70,9 +70,9 @@ theorem strictInterl_thetaa_thetab {f : ℝ[X]} (hf : IsPFPolynomial f) have hCab_ne : (C (a - b) : ℝ[X]) ≠ 0 := by grind have hCf_ne : C (a - b) * f ≠ 0 := mul_ne_zero hCab_ne hf0 have hpos_cf : HasPosLeadingCoeff (C (a - b) * f) := - (nonnegCoeffs_C_mul hab0.le hnn).pos_leadingCoeff hCf_ne + (hasNonnegCoeffs_C_mul hab0.le hnn).pos_leadingCoeff hCf_ne have hnn_g : HasNonnegCoeffs g := - HasNonnegCoeffs.add hnn.derivative.X_mul (nonnegCoeffs_C_mul hb.le hnn) + HasNonnegCoeffs.add hnn.derivative.X_mul (hasNonnegCoeffs_C_mul hb.le hnn) have hpos_g : HasPosLeadingCoeff g := hnn_g.pos_leadingCoeff hg0 have hsum : StrictInterl (C (a - b) * f + g) g := StrictInterl.add_of_right_of_posLeadingCoeff hcf hgg hpos_cf hpos_g diff --git a/RealRooted/EulerOperator/Polar.lean b/RealRooted/EulerOperator/Polar.lean index 7c3d802dd..e698dec14 100644 --- a/RealRooted/EulerOperator/Polar.lean +++ b/RealRooted/EulerOperator/Polar.lean @@ -36,7 +36,7 @@ theorem reciprocalShift_splits {D : ℕ} {p : ℝ[X]} (hp : p.Splits) (hdeg : p.natDegree ≤ D) : (reciprocalShift D p).Splits := by rw [reciprocalShift_eq_X_pow_mul_reverse hdeg] - exact DegreeDropReversal.splits_X_pow_mul_reverse hp _ + exact Polynomial.Splits.X_pow_mul_reverse hp _ /-- The polar theta operator preserves ordinary splitness in a finite degree box. -/ @@ -47,7 +47,7 @@ theorem polarTheta_splits_of_splits {N : ℕ} {p : ℝ[X]} have hshift : (reciprocalShift N p).Splits := reciprocalShift_splits hp hdeg have hderivative : (reciprocalShift N p).derivative = 0 ∨ (reciprocalShift N p).derivative.Splits := - eq_zero_or_splits_derivative (Or.inr hshift) + Or.inr hshift.derivative have hdegree : (reciprocalShift N p).derivative.natDegree ≤ N - 1 := by have hshift_degree : (reciprocalShift N p).natDegree ≤ N := by unfold reciprocalShift diff --git a/RealRooted/EulerOperator/Polar/Adjacent.lean b/RealRooted/EulerOperator/Polar/Adjacent.lean index ba0d1ea08..53a953622 100644 --- a/RealRooted/EulerOperator/Polar/Adjacent.lean +++ b/RealRooted/EulerOperator/Polar/Adjacent.lean @@ -79,13 +79,13 @@ theorem strictInterl_reverse_of_pf_of_natDegree_add_one C a * q.reverse + C b * p.reverse := by simp_all rw [← hreflect] - exact DegreeDropReversal.splits_reflect_of_splits hs hcomboDeg + exact Polynomial.Splits.reflect hs hcomboDeg have hprev0 : p.reverse ≠ 0 := by simp [hp0] have hqrev0 : q.reverse ≠ 0 := by simp [hq0] have hprevSplits : p.reverse.Splits := - DegreeDropReversal.splits_reverse hpq.1.2 + Polynomial.Splits.reverse hpq.1.2 have hqrevSplits : q.reverse.Splits := - DegreeDropReversal.splits_reverse hpq.2.1.2 + Polynomial.Splits.reverse hpq.2.1.2 have hptrail : p.natTrailingDegree = 0 := Polynomial.natTrailingDegree_eq_zero.mpr (Or.inr hpconst) have hqtrail : q.natTrailingDegree = 0 := @@ -120,8 +120,7 @@ theorem strictInterl_polarTheta_adjacent have hprevPF : IsPFPolynomial p.reverse := hp.reverse have hqrevPF : IsPFPolynomial q.reverse := hq.reverse have hXrev : StrictInterl (X * p.reverse) (X * q.reverse) := - StrictInterl.mul_X_both_of_roots_nonpos hrev - hprevPF.roots_nonpos hqrevPF.roots_nonpos + by simpa using hrev.mul_X_sub_C_both 0 let P := X * p.reverse let Q := X * q.reverse have hPdeg : P.natDegree = N + 1 := by diff --git a/RealRooted/EulerOperator/ScaledPolar.lean b/RealRooted/EulerOperator/ScaledPolar.lean index 53653e0cb..263d9e1a4 100644 --- a/RealRooted/EulerOperator/ScaledPolar.lean +++ b/RealRooted/EulerOperator/ScaledPolar.lean @@ -63,7 +63,7 @@ theorem comp_negXsq_splits_of_isPFPolynomial {h : ℝ[X]} (hh : IsPFPolynomial h by_cases hzero : h = 0 · simp [hzero] have hsplits : h.Splits := (hh.ne_zero_and_splits hzero).2 - have hroots_card : h.roots.card = h.natDegree := card_roots_of_splits hsplits + have hroots_card : h.roots.card = h.natDegree := Polynomial.splits_iff_card_roots.mp hsplits have hfactor : h = C h.leadingCoeff * (h.roots.map fun r => X - C r).prod := (C_leadingCoeff_mul_prod_multiset_X_sub_C hroots_card).symm rw [hfactor, Polynomial.mul_comp, Polynomial.C_comp, Polynomial.multiset_prod_comp] diff --git a/RealRooted/EulerianMixedCompatibility.lean b/RealRooted/EulerianMixedCompatibility.lean index e17aecd34..97a97f4fb 100644 --- a/RealRooted/EulerianMixedCompatibility.lean +++ b/RealRooted/EulerianMixedCompatibility.lean @@ -155,7 +155,7 @@ private theorem residue_div_neg_lt_eval_ratio_of_natDegree_ge_two eval_ratio_eq_sum_residues hgh.2.1.2 hh_nodup (by lia) hgdegree hxroot have hcard : 2 ≤ h.roots.toFinset.card := by rw [Multiset.toFinset_card_of_nodup hh_nodup, - card_roots_of_splits hgh.2.1.2] + Polynomial.splits_iff_card_roots.mp hgh.2.1.2] exact hhdeg obtain ⟨s, hs, hsr⟩ := h.roots.toFinset.exists_mem_ne (by lia) r have hsroots : s ∈ h.roots := Multiset.mem_toFinset.mp hs diff --git a/RealRooted/Favard.lean b/RealRooted/Favard.lean index c710cfa27..a44ec9e01 100644 --- a/RealRooted/Favard.lean +++ b/RealRooted/Favard.lean @@ -53,7 +53,7 @@ theorem favardInterlacing : have hF_deg : (aPoly * f + bPoly * g).natDegree = f.natDegree + 1 := by simpa [add_comm, hAf_deg] using - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hBg_lt_Af hAf_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hBg_lt_Af have hb_nonpos : ∀ r, f.IsRoot r → bPoly.eval r ≤ 0 := fun _ _ => by simpa [bPoly] using neg_nonpos.mpr (hβ n).le have hStrictInterl_step : StrictInterl f (aPoly * f + bPoly * g) := diff --git a/RealRooted/Favard/Affine/Basic.lean b/RealRooted/Favard/Affine/Basic.lean index 510e12411..9950db012 100644 --- a/RealRooted/Favard/Affine/Basic.lean +++ b/RealRooted/Favard/Affine/Basic.lean @@ -55,7 +55,7 @@ private theorem strictInterl_affine_favard_step {f g aPoly bPoly : ℝ[X]} hasPosLeadingCoeff_add_of_natDegree_lt_right hBg_lt_Af hAf_pos have hF_deg : (aPoly * f + bPoly * g).natDegree = f.natDegree + 1 := by simpa [add_comm, hAf_deg] using - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hBg_lt_Af hAf_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hBg_lt_Af have hStrictInterl_step : StrictInterl f (aPoly * f + bPoly * g) := strictInterl_of_interlaces_evalCoeff_nonpos (f := f) (g := g) (a := aPoly) (b := bPoly) diff --git a/RealRooted/FiniteFreeMultiplicative.lean b/RealRooted/FiniteFreeMultiplicative.lean index ceffb59fe..eb99cdbd1 100644 --- a/RealRooted/FiniteFreeMultiplicative.lean +++ b/RealRooted/FiniteFreeMultiplicative.lean @@ -166,7 +166,7 @@ theorem leadingCoeff_signedReciprocal_eq_coeff_zero theorem signedReciprocal_splits_of_splits {d : ℕ} {p : ℝ[X]} (hp : p.natDegree ≤ d) (hsplit : p.Splits) : (signedReciprocal d p).Splits := - DegreeDropReversal.splits_reflect_of_splits hsplit.comp_neg_X + Polynomial.Splits.reflect hsplit.comp_neg_X (natDegree_comp_neg_X_le hp) /-- Applying degree-`d` signed reciprocal reversal twice gives the parity diff --git a/RealRooted/FiniteFreeRootCount.lean b/RealRooted/FiniteFreeRootCount.lean index 952df0552..07a71d012 100644 --- a/RealRooted/FiniteFreeRootCount.lean +++ b/RealRooted/FiniteFreeRootCount.lean @@ -242,8 +242,8 @@ theorem RootwiseLE.of_strictInterl_sameDegree {p q : ℝ[X]} (hpq : StrictInterl (hdeg : p.natDegree = q.natDegree) : RootwiseLE p q := by rcases hpq with ⟨hp, hq, ss, rs, hss, hrs, hss_eq, hrs_eq, hshape⟩ have hlen : ss.length = rs.length := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hp.2, - ← Multiset.coe_card, hrs_eq, card_roots_of_splits hq.2, hdeg] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hp.2, + ← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hq.2, hdeg] have halt : ListAlternates ss rs := by rcases hshape with hbad | halt · exfalso @@ -579,8 +579,8 @@ theorem rootCountAbove_schurSzegoComp_reflect_le_add let M := max (listMax ps) (listMax qs) have hps_pair : ps.Pairwise (· ≤ ·) := Multiset.pairwise_sort _ _ have hqs_pair : qs.Pairwise (· ≤ ·) := Multiset.pairwise_sort _ _ - have hps_len : ps.length = d := by simp [ps, card_roots_of_splits hPsplit, hPdeg] - have hqs_len : qs.length = d := by simp [qs, card_roots_of_splits hQsplit, hQdeg] + have hps_len : ps.length = d := by simp [ps, Polynomial.splits_iff_card_roots.mp hPsplit, hPdeg] + have hqs_len : qs.length = d := by simp [qs, Polynomial.splits_iff_card_roots.mp hQsplit, hQdeg] have hlen : ps.length = qs.length := hps_len.trans hqs_len.symm have hMps : ∀ r ∈ ps, r ≤ M := fun _ hr => (le_listMax hr).trans (le_max_left _ _) diff --git a/RealRooted/FolkloreLemma.lean b/RealRooted/FolkloreLemma.lean index ce6eeaac6..200c04af5 100644 --- a/RealRooted/FolkloreLemma.lean +++ b/RealRooted/FolkloreLemma.lean @@ -88,9 +88,9 @@ private theorem strictInterl_sub_X_mul_core {f g : ℝ[X]} intro hfq rcases hfq with ⟨_, _, ss, rs, _, _, hss_eq, hrs_eq, hshape⟩ have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = q.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hq.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hq.2] lia have hqf : StrictInterl q f := by rcases hstrictInterl_or with hqf | hfq @@ -113,9 +113,9 @@ private theorem strictInterl_sub_X_mul_core {f g : ℝ[X]} intro hXgq rcases hXgq with ⟨_, _, ss, rs, _, _, hss_eq, hrs_eq, hshape⟩ have hss_len : ss.length = (X * g).natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hXg.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hXg.2] have hrs_len : rs.length = q.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hq.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hq.2] lia have hstrictInterl_qXg : StrictInterl q (X * g) := by rcases hstrictInterl_qXg_or with hqXg | hXgq diff --git a/RealRooted/GammaPencil/Invariants.lean b/RealRooted/GammaPencil/Invariants.lean index 6af9927c8..dee0910d2 100644 --- a/RealRooted/GammaPencil/Invariants.lean +++ b/RealRooted/GammaPencil/Invariants.lean @@ -196,7 +196,7 @@ theorem gammaPencil_hasNonnegCoeffs_add_two {a : ℝ} (ha : 0 ≤ a) (n : ℕ) : HasNonnegCoeffs (gammaPencil a (n + 2)) := by rw [gammaPencil, Polynomial.smul_eq_C_mul] exact (gammaU_hasNonnegCoeffs_add_two n).add - (nonnegCoeffs_C_mul ha (gammaV_hasNonnegCoeffs_add_two n)) + (hasNonnegCoeffs_C_mul ha (gammaV_hasNonnegCoeffs_add_two n)) theorem gammaPencil_natDegree_le_add_two (a : ℝ) (n : ℕ) : (gammaPencil a (n + 2)).natDegree ≤ (n + 2) / 2 := by diff --git a/RealRooted/GammaTransform/Basic.lean b/RealRooted/GammaTransform/Basic.lean index 905c22234..3b9c6317d 100644 --- a/RealRooted/GammaTransform/Basic.lean +++ b/RealRooted/GammaTransform/Basic.lean @@ -182,7 +182,7 @@ lemma hasNonnegCoeffs_gammaTransform {d : ℕ} {γ : ℝ[X]} (hγ : HasNonnegCoe unfold gammaTransform apply hasNonnegCoeffs_finsetSum intro i _ - exact nonnegCoeffs_C_mul (hγ i) (hasNonnegCoeffs_gammaBasisTerm d i) + exact hasNonnegCoeffs_C_mul (hγ i) (hasNonnegCoeffs_gammaBasisTerm d i) /-- A positive constant gamma coefficient makes every coefficient in the ambient degree box strictly positive. -/ @@ -194,7 +194,7 @@ theorem coeff_gammaTransform_pos_of_nonneg_of_coeff_zero_pos rw [Polynomial.finsetSum_coeff] apply Finset.sum_pos' · intro i hi - exact (nonnegCoeffs_C_mul (hγ i) + exact (hasNonnegCoeffs_C_mul (hγ i) (hasNonnegCoeffs_gammaBasisTerm d i)) k · refine ⟨0, by simp, ?_⟩ simp only [gammaBasisTerm_zero, coeff_C_mul] diff --git a/RealRooted/GammaTransform/Preservation.lean b/RealRooted/GammaTransform/Preservation.lean index 2d90ccb8c..b7d079223 100644 --- a/RealRooted/GammaTransform/Preservation.lean +++ b/RealRooted/GammaTransform/Preservation.lean @@ -19,7 +19,7 @@ lemma hasNonnegCoeffs_gammaQuadraticFactor {r : ℝ} (hr : r ≤ 0) : have hneg : 0 ≤ -r := by simp_all simpa [sub_eq_add_neg, add_comm, add_left_comm, add_assoc, mul_assoc] using hasNonnegCoeffs_X.add - (nonnegCoeffs_C_mul hneg (hasNonnegCoeffs_X_add_one.pow 2)) + (hasNonnegCoeffs_C_mul hneg (hasNonnegCoeffs_X_add_one.pow 2)) lemma isRealRooted_gammaQuadraticFactor {r : ℝ} (hr : r ≤ 0) : ((X - C r * (X + 1) ^ 2) ≠ 0 ∧ (X - C r * (X + 1) ^ 2).Splits) := by @@ -95,7 +95,7 @@ theorem isRealRooted_gammaTransform_of_isRealRooted_of_hasNonnegCoeffs exact isRealRooted_C_mul (isRealRooted_X_add_one_pow d).1 (isRealRooted_X_add_one_pow d).2 hcoeff_ne · have hroots_pos : 0 < γ.roots.card := by - rw [card_roots_of_splits hrr.2, hγdeg_eq] + rw [Polynomial.splits_iff_card_roots.mp hrr.2, hγdeg_eq] lia obtain ⟨r, hr_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hr_root : γ.IsRoot r := (mem_roots hrr.1).mp hr_mem @@ -197,7 +197,7 @@ theorem isRealRooted_and_hasRootsNonpos_of_isRealRooted_gammaTransform_minimal (natDegree_gammaTransform_le (2 * n) δ) (by simp_all) have hroots_pos : 0 < (gammaTransform (2 * n) δ).roots.card := by - rw [card_roots_of_splits hpδ.2, htop_deg] + rw [Polynomial.splits_iff_card_roots.mp hpδ.2, htop_deg] lia obtain ⟨x, hx_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hx_root : (gammaTransform (2 * n) δ).IsRoot x := (mem_roots hpδ.1).mp hx_mem @@ -305,7 +305,7 @@ theorem isRealRooted_and_hasRootsNonpos_gammaTransform_of_isRealRooted_of_hasRoo rw [roots_C_mul _ hcoeff_ne] at hr exact roots_nonpos_of_hasNonnegCoeffs (hasNonnegCoeffs_X_add_one.pow d) r hr · have hroots_pos : 0 < δ.roots.card := by - rw [card_roots_of_splits hδ_rr.2, hδdeg] + rw [Polynomial.splits_iff_card_roots.mp hδ_rr.2, hδdeg] lia obtain ⟨r, hr_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hr_root : δ.IsRoot r := (mem_roots hδ_rr.1).mp hr_mem diff --git a/RealRooted/GammaTransform/ProperPosition.lean b/RealRooted/GammaTransform/ProperPosition.lean index 3d8c2ce77..ddcf979ec 100644 --- a/RealRooted/GammaTransform/ProperPosition.lean +++ b/RealRooted/GammaTransform/ProperPosition.lean @@ -60,7 +60,7 @@ private lemma length_preferredRoots (preferredRoots d γ).length = γ.natDegree := by have hcoe := coe_map_gammaRootMap_preferredRoots hγdeg hγ hγneg have hcard := congrArg Multiset.card hcoe - simpa [card_roots_of_splits hγsplits] using hcard + simpa [Polynomial.splits_iff_card_roots.mp hγsplits] using hcard private lemma map_gammaRootMap_preferredRoots_pairwise (d : ℕ) (γ : ℝ[X]) : ((preferredRoots d γ).map gammaRootMap).Pairwise (· ≤ ·) := by diff --git a/RealRooted/GammaTransform/RootMap.lean b/RealRooted/GammaTransform/RootMap.lean index cd114eb3b..62a76d43d 100644 --- a/RealRooted/GammaTransform/RootMap.lean +++ b/RealRooted/GammaTransform/RootMap.lean @@ -167,7 +167,7 @@ lemma hasRootsNonpos_of_dvd {p q : ℝ[X]} HasRootsNonpos q := by intro r hr have hrq : q.IsRoot r := (mem_roots hq0).mp hr - have hrp : p.IsRoot r := IsRoot.of_dvd hqp hrq + have hrp : p.IsRoot r := hrq.dvd hqp exact hp_nonpos r ((mem_roots hp0).mpr hrp) lemma HasRootsNonpos.mul {p q : ℝ[X]} diff --git a/RealRooted/GarloffWagner/Iterated.lean b/RealRooted/GarloffWagner/Iterated.lean index 7b98510b8..c0bd75b41 100644 --- a/RealRooted/GarloffWagner/Iterated.lean +++ b/RealRooted/GarloffWagner/Iterated.lean @@ -310,7 +310,7 @@ theorem divFactorialShift_splits_of_splits {f : ℝ[X]} (hf0 : f ≠ 0) (hfs : f rw [hfC] exact divFactorialShift_C_splits (f.coeff 0) k · have hroots_pos : 0 < f.roots.card := by - rw [card_roots_of_splits hfs, hfdeg] + rw [Polynomial.splits_iff_card_roots.mp hfs, hfdeg] exact Nat.pos_of_ne_zero hn0 obtain ⟨u, hu_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hu_root : f.IsRoot u := (mem_roots hf0).mp hu_mem @@ -379,7 +379,7 @@ private theorem divFactorialShift_hasSimpleRootsExcept_zero rw [hfC, hb] exact hasSimpleRootsExcept_zero_C_mul_X_pow hb_ne k · have hroots_pos : 0 < f.roots.card := by - rw [card_roots_of_splits hfs, hfdeg] + rw [Polynomial.splits_iff_card_roots.mp hfs, hfdeg] exact Nat.pos_of_ne_zero hn0 obtain ⟨u, hu_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hu_root : f.IsRoot u := (mem_roots hf0).mp hu_mem diff --git a/RealRooted/GarloffWagner/Theorem12.lean b/RealRooted/GarloffWagner/Theorem12.lean index 57f7ced0e..c31037ac4 100644 --- a/RealRooted/GarloffWagner/Theorem12.lean +++ b/RealRooted/GarloffWagner/Theorem12.lean @@ -135,7 +135,7 @@ private theorem factorialHadamardProduct_pf_right_linearFactor_of_derivative_int have hneg : HasNonnegCoeffs (-(C u * factorialHadamardProduct f p)) := by simpa [neg_mul, C_neg] using - nonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hF.hasNonnegCoeffs + hasNonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hF.hasNonnegCoeffs exact hD.hasNonnegCoeffs.X_mul.add hneg by_cases hF0 : F = 0 · rw [factorialHadamardProduct_X_sub_C_mul_right] @@ -163,7 +163,7 @@ theorem HasNonnegCoeffs.weightedSum : have htail_nn : ∀ ap ∈ l, HasNonnegCoeffs ap.2 := fun ap hap => hnn ap (by simp [hap]) simpa [weightedSum_cons] using - (nonnegCoeffs_C_mul ha hp).add + (hasNonnegCoeffs_C_mul ha hp).add (HasNonnegCoeffs.weightedSum l htail_nonneg htail_nn) /-- Zero-aware weighted common-right cone closure. -/ @@ -190,7 +190,7 @@ theorem interl_weightedSum_right_of_nonneg : have htail_strictInterl_sum : Interl (weightedSum l) h := interl_weightedSum_right_of_nonneg l h htail_nonneg htail_strictInterl htail_nn have hhead_nn : HasNonnegCoeffs (C a * p) := - nonnegCoeffs_C_mul ha hp_nn + hasNonnegCoeffs_C_mul ha hp_nn have htail_sum_nn : HasNonnegCoeffs (weightedSum l) := HasNonnegCoeffs.weightedSum l htail_nonneg htail_nn simpa [weightedSum_cons] using @@ -290,7 +290,7 @@ theorem divFactorial_sub_C_mul_derivative_interl_self {p : ℝ[X]} {u : ℝ} hpL.derivative.hasNonnegCoeffs have hscaled_nn : HasNonnegCoeffs (C (-u) * derivative (divFactorial p)) := - nonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hDnn + hasNonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hDnn have hsum : Interl (divFactorial p + C (-u) * derivative (divFactorial p)) (divFactorial p) := interl_add_left_of_common_right_of_nonneg hpL.interl_self hscaled @@ -312,7 +312,7 @@ theorem divFactorial_sub_C_mul_derivative_pf {p : ℝ[X]} {u : ℝ} change HasNonnegCoeffs (divFactorial p - C u * derivative (divFactorial p)) have hscaled_nn : HasNonnegCoeffs (C (-u) * derivative (divFactorial p)) := - nonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hDnn + hasNonnegCoeffs_C_mul (by linarith : 0 ≤ -u) hDnn simpa [sub_eq_add_neg, C_neg, neg_mul] using hpL.hasNonnegCoeffs.add hscaled_nn by_cases hT0 : T = 0 diff --git a/RealRooted/GeneralizedSnakePosets/Narayana/JacobiTransport.lean b/RealRooted/GeneralizedSnakePosets/Narayana/JacobiTransport.lean index 7ef57b6f3..071076ee5 100644 --- a/RealRooted/GeneralizedSnakePosets/Narayana/JacobiTransport.lean +++ b/RealRooted/GeneralizedSnakePosets/Narayana/JacobiTransport.lean @@ -297,8 +297,7 @@ theorem narayanaDifference_modified_natDegree {n : ℕ} (hn : 1 ≤ n) : modifiedNarayanaPolynomial_natDegree] lia simpa [modifiedNarayanaPolynomial_natDegree] using - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg - (modifiedNarayanaPolynomial_posLeadingCoeff n) + Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg /-- The named difference `Q_n = P_n - P_{n-1}` has positive leading coefficient for the concrete modified Narayana family. -/ @@ -344,7 +343,7 @@ private theorem affineLinear_natDegree_of_lam_pos rw [Polynomial.natDegree_C, Polynomial.natDegree_C_mul hlam.ne', Polynomial.natDegree_X] norm_num - rw [natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg hCX_pos, + rw [Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg, Polynomial.natDegree_C_mul hlam.ne', Polynomial.natDegree_X] private theorem affineLinear_posLeadingCoeff_of_lam_pos @@ -413,7 +412,7 @@ theorem modifiedNarayana_linear_hasNonnegCoeffs HasNonnegCoeffs ((C lam * X + C mu) * modifiedNarayanaPolynomial (m - 1)) := by have hlin : HasNonnegCoeffs (C lam * X + C mu : ℝ[X]) := - (nonnegCoeffs_C_mul hlam hasNonnegCoeffs_X).add (hasNonnegCoeffs_C hmu) + (hasNonnegCoeffs_C_mul hlam hasNonnegCoeffs_X).add (hasNonnegCoeffs_C hmu) exact hlin.mul (modifiedNarayanaPolynomial_hasNonnegCoeffs (m - 1)) /-- The left-hand polynomial in Braun--Jal's shifted affine Narayana interlacing lemma has @@ -497,7 +496,7 @@ theorem affineModifiedNarayanaShifted_left_natDegree rw [hQ_deg] exact lt_of_le_of_lt hA_le (Nat.sub_one_lt (Nat.ne_of_gt hm)) simpa [hQ_deg] using - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hA_lt hQ_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hA_lt /-- The left-hand polynomial in Braun--Jal's shifted affine Narayana interlacing lemma is nonzero. -/ diff --git a/RealRooted/GeneralizedSnakePosets/Narayana/PFFacts.lean b/RealRooted/GeneralizedSnakePosets/Narayana/PFFacts.lean index 62fe2e5eb..14f519956 100644 --- a/RealRooted/GeneralizedSnakePosets/Narayana/PFFacts.lean +++ b/RealRooted/GeneralizedSnakePosets/Narayana/PFFacts.lean @@ -98,7 +98,7 @@ theorem modifiedNarayanaPolynomial_six_exists_ordered_roots : Multiset.sort_eq .., Multiset.pairwise_sort ..⟩ have hlen : rs.length = 6 := by rw [← Multiset.coe_card, hrs_eq, - card_roots_of_splits modifiedNarayanaPolynomial_six_splits] + Polynomial.splits_iff_card_roots.mp modifiedNarayanaPolynomial_six_splits] exact modifiedNarayanaPolynomial_six_natDegree match rs, hlen, hrs_eq, hrs_sorted with | [a, b, c, d, e, r], _, hrs_eq, hrs_sorted => diff --git a/RealRooted/GeneralizedSnakePosets/Narayana/ShiftedDifferenceInterlacingAnalytic.lean b/RealRooted/GeneralizedSnakePosets/Narayana/ShiftedDifferenceInterlacingAnalytic.lean index 5ae9729a1..e6a2012cb 100644 --- a/RealRooted/GeneralizedSnakePosets/Narayana/ShiftedDifferenceInterlacingAnalytic.lean +++ b/RealRooted/GeneralizedSnakePosets/Narayana/ShiftedDifferenceInterlacingAnalytic.lean @@ -197,12 +197,12 @@ theorem auxiliaryGPencil_hasNonnegCoeffs_of_difference have hlam_term : HasNonnegCoeffs (C lam * (X * FiniteSkewBoard.auxiliaryG (m - 1))) := - nonnegCoeffs_C_mul hlam + hasNonnegCoeffs_C_mul hlam (FiniteSkewBoard.auxiliaryG_hasNonnegCoeffs (m - 1)).X_mul have hnu_term : HasNonnegCoeffs (C (nu + 1) * FiniteSkewBoard.auxiliaryG (m - 1)) := - nonnegCoeffs_C_mul hnu_one + hasNonnegCoeffs_C_mul hnu_one (FiniteSkewBoard.auxiliaryG_hasNonnegCoeffs (m - 1)) rw [show (C lam * X + C nu) * FiniteSkewBoard.auxiliaryG (m - 1) + diff --git a/RealRooted/Graph/IndependencePolynomial/Basic.lean b/RealRooted/Graph/IndependencePolynomial/Basic.lean index fe3ea06ba..e032949a6 100644 --- a/RealRooted/Graph/IndependencePolynomial/Basic.lean +++ b/RealRooted/Graph/IndependencePolynomial/Basic.lean @@ -108,7 +108,7 @@ theorem weightedIndepPolyOn_hasNonnegCoeffs {V : Type u} [DecidableEq V] · intro v t hv ih hsub rw [Finset.prod_insert hv] have hv_nonneg : HasNonnegCoeffs (C (wt v)) := by - simpa using nonnegCoeffs_C_mul (hwt v (hsub (Finset.mem_insert_self v t))) + simpa using hasNonnegCoeffs_C_mul (hwt v (hsub (Finset.mem_insert_self v t))) hasNonnegCoeffs_one have hsub_t : t ⊆ S := fun w hw => hsub (Finset.mem_insert.mpr (Or.inr hw)) exact hv_nonneg.mul (ih hsub_t) diff --git a/RealRooted/Hadamard/Basic.lean b/RealRooted/Hadamard/Basic.lean index 7412edb4d..5b1c66f9f 100644 --- a/RealRooted/Hadamard/Basic.lean +++ b/RealRooted/Hadamard/Basic.lean @@ -483,11 +483,10 @@ theorem reflect_iterate_derivative_reflect_splits_of_splits (hsplit : p.Splits) : (reflect 3 ((derivative^[n - 3]) (reflect n p))).Splits := by have hreflect : (reflect n p).Splits := - DegreeDropReversal.splits_reflect_of_splits hsplit hpdeg + Polynomial.Splits.reflect hsplit hpdeg have hqsplit : ((derivative^[n - 3]) (reflect n p)).Splits := - (iterate_derivative_eq_zero_or_splits hreflect (n - 3)).elim - (fun h => by simp [h]) id - exact DegreeDropReversal.splits_reflect_of_splits hqsplit + hreflect.iterate_derivative (n - 3) + exact Polynomial.Splits.reflect hqsplit (natDegree_iterate_derivative_reflect_le_three hn hpdeg) /-- The level-`n` degree-three Jensen section of a splitting polynomial is diff --git a/RealRooted/Hadamard/Grace.lean b/RealRooted/Hadamard/Grace.lean index 196f778a3..e402c65a7 100644 --- a/RealRooted/Hadamard/Grace.lean +++ b/RealRooted/Hadamard/Grace.lean @@ -283,8 +283,8 @@ theorem splits_diagonalOperator_pred (n : Nat) (hn : 1 ≤ n) {q : ℝ[X]} (diagonalOperator (fun k ↦ ((n : ℝ) - k) / n) q).Splits := by rw [diagonalOperator_pred_eq_reflect_derivative n hn q hq] refine (Polynomial.Splits.C (R := ℝ) _).mul <| - DegreeDropReversal.splits_reflect_of_splits - (Polynomial.Splits.derivative ((DegreeDropReversal.splits_reflect_iff hq).2 hsplit)) ?_ + Polynomial.Splits.reflect + (Polynomial.Splits.derivative ((Polynomial.splits_reflect_iff hq).2 hsplit)) ?_ rw [(reflect n q).natDegree_derivative] simpa [max_eq_left hq] using Nat.sub_le_sub_right (Polynomial.natDegree_reflect_le (N := n) (p := q)) 1 @@ -370,10 +370,10 @@ theorem splits_schurSzegoComp_of_isPF (n : Nat) : DegreeDropReversal.natDegree_reflect_eq_of_coeff_zero_ne hp hp00 have hRp_ne : reflect n p ≠ 0 := by simp [*] have hRp_split : (reflect n p).Splits := - DegreeDropReversal.splits_reflect_of_splits hsplit hp + Polynomial.Splits.reflect hsplit hp suffices hcore : (schurSzegoComp n (reflect n f) (reflect n p)).Splits by rw [← reflect_schurSzegoComp] at hcore - exact (DegreeDropReversal.splits_reflect_iff (natDegree_schurSzegoComp_le n f p)).mp hcore + exact (Polynomial.splits_reflect_iff (natDegree_schurSzegoComp_le n f p)).mp hcore by_cases hfn : f.natDegree = n · have hRf_coeff0 : (reflect n f).coeff 0 ≠ 0 := by rw [coeff_reflect, revAt_zero, ← hfn] diff --git a/RealRooted/Hadamard/Newton.lean b/RealRooted/Hadamard/Newton.lean index c703479c5..b46037501 100644 --- a/RealRooted/Hadamard/Newton.lean +++ b/RealRooted/Hadamard/Newton.lean @@ -26,7 +26,7 @@ theorem two_natDegree_mul_coeff_zero_mul_coeff_two_le_coeff_one_sq_of_splits ((p.natDegree : ℝ) - 1) * p.coeff 1 ^ 2 := by set t := p.roots.map Neg.neg with ht_def have htcard : Multiset.card t = p.natDegree := by - rw [ht_def, Multiset.card_map, card_roots_of_splits hs] + rw [ht_def, Multiset.card_map, Polynomial.splits_iff_card_roots.mp hs] have h1d : 1 ≤ p.natDegree := le_trans one_le_two hdeg have hc0 := coeff_eq_leadingCoeff_mul_esymm_neg_roots hs (k := 0) (Nat.zero_le _) have hc1 := coeff_eq_leadingCoeff_mul_esymm_neg_roots hs (k := 1) h1d @@ -115,7 +115,7 @@ theorem newton_three_coeff_one_coeff_three_of_splits 2 * ((p.natDegree : ℝ) - 2) * p.coeff 2 ^ 2 := by set t := p.roots.map Neg.neg with ht_def have htcard : Multiset.card t = p.natDegree := by - rw [ht_def, Multiset.card_map, card_roots_of_splits hs] + rw [ht_def, Multiset.card_map, Polynomial.splits_iff_card_roots.mp hs] have h1d : 1 ≤ p.natDegree := by lia have h2d : 2 ≤ p.natDegree := by lia have hc1 := coeff_eq_leadingCoeff_mul_esymm_neg_roots hs (k := 1) h1d diff --git a/RealRooted/Hadamard/SchurSzegoSimple.lean b/RealRooted/Hadamard/SchurSzegoSimple.lean index b30dffbe9..86218d04b 100644 --- a/RealRooted/Hadamard/SchurSzegoSimple.lean +++ b/RealRooted/Hadamard/SchurSzegoSimple.lean @@ -450,7 +450,7 @@ private theorem gap_lemma {p : ℝ[X]} (hp : p.Splits) : /-- `reflect` preserves splitting. -/ private theorem splits_reflect {p : ℝ[X]} (hp : p.Splits) {N : ℕ} (hN : p.natDegree ≤ N) : (reflect N p).Splits := - RealRooted.DegreeDropReversal.splits_reflect_of_splits hp hN + Polynomial.Splits.reflect hp hN end SchurSzegoAristotle diff --git a/RealRooted/Hadamard/SchurSzegoStrict.lean b/RealRooted/Hadamard/SchurSzegoStrict.lean index cd7e1f7e5..502c7dc0f 100644 --- a/RealRooted/Hadamard/SchurSzegoStrict.lean +++ b/RealRooted/Hadamard/SchurSzegoStrict.lean @@ -295,7 +295,7 @@ theorem strictInterl_schurSzegoComp_of_roots_neg {n : ℕ} {f g Q : ℝ[X]} (hn intro hfzero r hr have haroots : a.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hasplit, hadegree, hfzero] + rw [Polynomial.splits_iff_card_roots.mp hasplit, hadegree, hfzero] have := (mem_roots hane).mpr hr.1 simp [haroots] at this by_cases hgzero : g.natDegree = 0 @@ -304,10 +304,10 @@ theorem strictInterl_schurSzegoComp_of_roots_neg {n : ℕ} {f g Q : ℝ[X]} (hn lia have haroots : a.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hasplit, hadegree, hfzero] + rw [Polynomial.splits_iff_card_roots.mp hasplit, hadegree, hfzero] have hbroots : b.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hbsplit, hbdegree, hgzero] + rw [Polynomial.splits_iff_card_roots.mp hbsplit, hbdegree, hgzero] refine ⟨?_, fun r hr hbr => hno_of_f_const hfzero r ⟨hr, hbr⟩⟩ rcases hweakOr with hab | hba · exact hab diff --git a/RealRooted/Hermite/Poulain.lean b/RealRooted/Hermite/Poulain.lean index 3c02e45cb..270b30ed8 100644 --- a/RealRooted/Hermite/Poulain.lean +++ b/RealRooted/Hermite/Poulain.lean @@ -200,7 +200,7 @@ theorem applyAsDifferentialOperator_X_add_C_eq_zero_or_splits {a : ℝ} {g : ℝ (applyAsDifferentialOperator (X + C a) g).Splits := by rw [applyAsDifferentialOperator_X_add_C, add_comm] rcases eq_or_ne a 0 with rfl | ha - · simpa using eq_zero_or_splits_derivative (.inr hg) + · simpa using (Or.inr hg.derivative : g.derivative = 0 ∨ g.derivative.Splits) · exact .inr (splits_C_mul_add_derivative hg ha) /-- Hermite--Poulain theorem target, zero-aware because a differential operator diff --git a/RealRooted/HermiteBiehler/ConverseLowDegree.lean b/RealRooted/HermiteBiehler/ConverseLowDegree.lean index 3e540e9c7..3d8932d0d 100644 --- a/RealRooted/HermiteBiehler/ConverseLowDegree.lean +++ b/RealRooted/HermiteBiehler/ConverseLowDegree.lean @@ -789,8 +789,8 @@ theorem strictInterl_of_stable_two_one {f g : ℝ[X]} have : b₂ * (-c₂ / b₂) = -c₂ := by field_simp rw [this, C_neg, sub_neg_eq_add] have hgroots : g.roots = {-c₂ / b₂} := by rw [hgfact, roots_C_mul _ hb₂_ne, roots_X_sub_C] - have hfs : f.Splits := splits_of_card_roots (by rw [hfroots, hf₂]; simp) - have hgs : g.Splits := splits_of_card_roots (by rw [hgroots, hg₁]; simp) + have hfs : f.Splits := Polynomial.splits_iff_card_roots.mpr (by rw [hfroots, hf₂]; simp) + have hgs : g.Splits := Polynomial.splits_iff_card_roots.mpr (by rw [hgroots, hg₁]; simp) obtain ⟨h₁, h₂⟩ := interlace_core_two_one ha hv₁ hv₂ hb₂_pos hb₁ hb₂ hc₁ hc₂ refine ⟨⟨h_g_ne, hgs⟩, ⟨h_f_ne, hfs⟩, [-c₂ / b₂], diff --git a/RealRooted/HermiteBiehler/Forward.lean b/RealRooted/HermiteBiehler/Forward.lean index 1d3a83526..2ed901bd9 100644 --- a/RealRooted/HermiteBiehler/Forward.lean +++ b/RealRooted/HermiteBiehler/Forward.lean @@ -45,7 +45,7 @@ theorem logDeriv_complexify_im_neg {p : ℝ[X]} (hp : p.Splits) (hp₀ : p ≠ 0 ((complexify p).derivative.eval z / (complexify p).eval z).im < 0 := by rw [logDeriv_complexify_eq_sum hp hp₀ hz, multiset_sum_im, Multiset.map_map] apply multiset_sum_neg - · rw [Ne, Multiset.map_eq_zero, ← Multiset.card_eq_zero, card_roots_of_splits hp] + · rw [Ne, Multiset.map_eq_zero, ← Multiset.card_eq_zero, Polynomial.splits_iff_card_roots.mp hp] lia · intro x hx simp only [Multiset.mem_map] at hx @@ -128,7 +128,7 @@ private theorem strictInterl_roots_deg1 (f g : ℝ[X]) (hpq : StrictInterl g f) (hd : f.natDegree = 1) : g.roots = 0 ∨ ∃ r s, f.roots = {s} ∧ g.roots = {r} ∧ r ≤ s := by obtain ⟨⟨hg₀, hgs⟩, ⟨hf₀, hfs⟩, ss, rs, hss, hrs, hsseq, hrseq, hshape⟩ := hpq - have hfcard : f.roots.card = 1 := by rw [card_roots_of_splits hfs, hd] + have hfcard : f.roots.card = 1 := by rw [Polynomial.splits_iff_card_roots.mp hfs, hd] have hrslen : rs.length = 1 := by have : (rs : Multiset ℝ).card = 1 := by simp [*] simpa using this @@ -154,12 +154,14 @@ theorem hermiteBiehlerForwardPos_of_natDegree_le_one {f g : ℝ[X]} · have hd₀ : f.natDegree = 0 := by lia have hgr : g.roots = 0 := by obtain ⟨_, _, ss, rs, _, _, hsseq, hrseq, hshape⟩ := hpq - have hfcard : f.roots.card = 0 := by rw [card_roots_of_splits hfs, hd₀] + have hfcard : f.roots.card = 0 := by + rw [Polynomial.splits_iff_card_roots.mp hfs, hd₀] simp_all intro z hz hroot rw [eval_hermiteBiehlerPolynomial, eval_complexify_eq_prod hfs, eval_complexify_eq_prod hgs, hgr] at hroot - have hfr : f.roots = 0 := by rw [← Multiset.card_eq_zero, card_roots_of_splits hfs, hd₀] + have hfr : f.roots = 0 := by + rw [← Multiset.card_eq_zero, Polynomial.splits_iff_card_roots.mp hfs, hd₀] rw [hfr] at hroot simp only [Multiset.map_zero, Multiset.prod_zero, mul_one] at hroot have h_im : @@ -172,7 +174,8 @@ theorem hermiteBiehlerForwardPos_of_natDegree_le_one {f g : ℝ[X]} apply stable_of_im_ratio_nonpos hf₀ hfs intro z hz rcases strictInterl_roots_deg1 f g hpq hd₁ with hgr | ⟨r, s, hfr, hgr, hrs⟩ - · obtain ⟨s, hfr⟩ := Multiset.card_eq_one.mp (by rw [card_roots_of_splits hfs, hd₁]) + · obtain ⟨s, hfr⟩ := Multiset.card_eq_one.mp (by + rw [Polynomial.splits_iff_card_roots.mp hfs, hd₁]) exact im_ratio_deg1_deg0 f g z hz hfs hgs hf hg s hfr hgr · exact im_ratio_deg1_deg1 f g z hz hfs hgs hf hg s r hfr hgr hrs @@ -294,8 +297,8 @@ theorem im_ratio_nonpos {f g : ℝ[X]} (hpq : StrictInterl g f) {z : ℂ} (hz : 0 < z.im) : ((complexify g).eval z / (complexify f).eval z).im ≤ 0 := by obtain ⟨⟨hg₀, hgs⟩, ⟨-, hfs⟩, ss, rs, -, -, hsseq, hrseq, hshape⟩ := id hpq - have hgc : g.roots.card = g.natDegree := card_roots_of_splits hgs - have hfc : f.roots.card = f.natDegree := card_roots_of_splits hfs + have hgc : g.roots.card = g.natDegree := Polynomial.splits_iff_card_roots.mp hgs + have hfc : f.roots.card = f.natDegree := Polynomial.splits_iff_card_roots.mp hfs rcases hshape with ⟨hlen, _⟩ | ⟨hlen, _⟩ · have hdd : g.natDegree + 1 = f.natDegree := by rw [← hgc, ← hfc, ← hsseq, ← hrseq] diff --git a/RealRooted/HermiteBiehler/OrientedPencil.lean b/RealRooted/HermiteBiehler/OrientedPencil.lean index dc548dcd9..7ff437391 100644 --- a/RealRooted/HermiteBiehler/OrientedPencil.lean +++ b/RealRooted/HermiteBiehler/OrientedPencil.lean @@ -37,10 +37,10 @@ theorem strictInterl_of_allComboRealRooted_of_wronskian_nonneg by_cases hdeg0 : f.natDegree = 0 · have hfroots : f.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hfrr.2, hdeg0] + rw [Polynomial.splits_iff_card_roots.mp hfrr.2, hdeg0] have hgroots : g.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hgrr.2, ← hsame, hdeg0] + rw [Polynomial.splits_iff_card_roots.mp hgrr.2, ← hsame, hdeg0] simp [hfroots, hgroots] · let n := f.natDegree have hn : 1 ≤ n := by simp only [n]; lia diff --git a/RealRooted/HosterStump/Chow.lean b/RealRooted/HosterStump/Chow.lean index 65e3673e0..5b713f574 100644 --- a/RealRooted/HosterStump/Chow.lean +++ b/RealRooted/HosterStump/Chow.lean @@ -396,7 +396,7 @@ private theorem isRealRooted_sum_C_mul_of_interl {n : ℕ} (F : ℕ → ℝ[X]) refine ⟨isInterlacingSeq0_iff_pairwise.2 hpair, ?_⟩ intro f hf obtain ⟨k, -, rfl⟩ := List.mem_map.1 hf - exact nonnegCoeffs_C_mul (hh k) (hnn k) + exact hasNonnegCoeffs_C_mul (hh k) (hnn k) have hreal : ∀ f ∈ gs, f ≠ 0 → (f ≠ 0 ∧ f.Splits) := by intro f hf hf0 obtain ⟨k, hk, rfl⟩ := List.mem_map.1 hf @@ -415,7 +415,7 @@ private lemma coeff_zero_sum_C_mul_refined (n : ℕ) (h : ℕ → ℝ) (T : Fins private lemma hasNonnegCoeffs_sum_C_mul_refined (n : ℕ) {h : ℕ → ℝ} (hh : ∀ k, 0 ≤ h k) (S T : Finset ℕ) : HasNonnegCoeffs (∑ k ∈ Finset.range (n + 1), C (h k) * refined n k S T) := hasNonnegCoeffs_finsetSum _ _ fun k _ => - nonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k S T) + hasNonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k S T) private lemma natDegree_sum_C_mul_refined_le (n : ℕ) (h : ℕ → ℝ) {T : Finset ℕ} {b : ℕ} (hcard : ∀ D ∈ isolatedSubsets T, D.card ≤ b) : @@ -546,8 +546,8 @@ private theorem strictInterl_sum_refined_Icc_sum_refined_range {n : ℕ} (hn : 2 C (h k) * refined n k ∅ ((Finset.range n).erase 0)) (∑ k ∈ Finset.range (n + 1), C (h k) * bot n (Finset.range n) k) := by refine Interl.finsetSum_pairwise_of_nonneg _ _ _ _ (fun i hi j hj => ?_) - (fun k _ => nonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k ∅ _)) - (fun k _ => nonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k {0} _)) + (fun k _ => hasNonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k ∅ _)) + (fun k _ => hasNonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k {0} _)) have hi' := Finset.mem_range.1 hi have hj' := Finset.mem_range.1 hj exact ((hD.top_bot i j (by lia) (by lia)).C_mul_left_of_nonneg (hh i)).C_mul_right_of_nonneg @@ -566,7 +566,7 @@ private theorem strictInterl_sum_refined_Icc_sum_refined_range {n : ℕ} (hn : 2 exact interl_add_right_of_common_left_of_nonneg (Interl.refl fun _ => hsp3) hbot (hasNonnegCoeffs_sum_C_mul_refined n hh _ _) (hasNonnegCoeffs_finsetSum _ _ fun k _ => - nonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k {0} _)) + hasNonnegCoeffs_C_mul (hh k) (hasNonnegCoeffs_refined n k {0} _)) exact hint.toStrictInterl_of_ne hne3 hne2 diff --git a/RealRooted/HosterStump/Sequence.lean b/RealRooted/HosterStump/Sequence.lean index d204b4002..984458e93 100644 --- a/RealRooted/HosterStump/Sequence.lean +++ b/RealRooted/HosterStump/Sequence.lean @@ -225,7 +225,8 @@ private theorem interl_X_mul_add_add_X_mul {P M W : ℝ[X]} (hPM : Interl P M) Interl (X * P + (M + W)) (X * (P + M) + W) := by have key := Interl.window_three (f₁ := M) (f₂ := W) (f₃ := X * P) (f₄ := X * M) hMW (interl_mul_X_of_interl hPM nnP nnM) (interl_mul_X_of_interl (Interl.refl sM) nnM nnM) - (interl_mul_X_of_interl hMW nnM nnW) (hPM.mul_X_both_of_nonneg nnP nnM) nnM nnW nnP.X_mul + (interl_mul_X_of_interl hMW nnM nnW) + (hPM.mul_X_both_of_nonneg nnP nnM) nnM nnW nnP.X_mul nnM.X_mul (splits_add_X_mul_of_interl hPW nnP nnW sP sW) rw [show X * P + (M + W) = M + W + X * P by ring, show X * (P + M) + W = W + X * P + X * M by ring] diff --git a/RealRooted/Interlacing/ConeBounds.lean b/RealRooted/Interlacing/ConeBounds.lean index a5a5a0cf5..cf016e004 100644 --- a/RealRooted/Interlacing/ConeBounds.lean +++ b/RealRooted/Interlacing/ConeBounds.lean @@ -30,11 +30,6 @@ Note that the endpoints must be compared with themselves, so the statement also consumes reflexivity of `StrictInterl` on the real-rooted members. -/ -/-- Compatibility name for the foundational nonnegative-scaling lemma. -/ -theorem hasNonnegCoeffs_C_mul {a : ℝ} {p : ℝ[X]} (ha : 0 ≤ a) - (hp : HasNonnegCoeffs p) : HasNonnegCoeffs (C a * p) := - nonnegCoeffs_C_mul ha hp - /-- **Branden--Saud Leite Lemma 3.1(1).** A nonnegative combination of an interlacing sequence is caught between its first and last members. -/ theorem interl_weightedSum_cone {n : ℕ} (f : ℕ → ℝ[X]) (lam : ℕ → ℝ) @@ -49,7 +44,7 @@ theorem interl_weightedSum_cone {n : ℕ} (f : ℕ → ℝ[X]) (lam : ℕ → intro i hi simpa [Nat.lt_succ_iff] using Finset.mem_range.mp hi have hnn' : ∀ i ∈ Finset.range (n + 1), HasNonnegCoeffs (C (lam i) * f i) := - fun i hi => nonnegCoeffs_C_mul (hlam i) (hnn i (hmem i hi)) + fun i hi => hasNonnegCoeffs_C_mul (hlam i) (hnn i (hmem i hi)) refine ⟨?_, ?_⟩ · refine Interl.finsetSum_left_of_nonneg _ _ _ ?_ hnn' intro i hi diff --git a/RealRooted/Interlacing/NegativeRoots.lean b/RealRooted/Interlacing/NegativeRoots.lean index 1712e73d2..896cd9a2f 100644 --- a/RealRooted/Interlacing/NegativeRoots.lean +++ b/RealRooted/Interlacing/NegativeRoots.lean @@ -53,7 +53,7 @@ theorem roots_neg_of_interlaces_of_eval_zero_pos {g f : ℝ[X]} ∀ r, f.IsRoot r → r < 0 := by obtain ⟨hf, hg, _, rs, ss, _, _, hrs_eq, hss_eq, hint⟩ := hgf have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_ne : rs ≠ [] := by grind have hss_neg : ∀ s ∈ ss, s < 0 := by intro s hs @@ -64,7 +64,7 @@ theorem roots_neg_of_interlaces_of_eval_zero_pos {g f : ℝ[X]} listInterlaces_dropLast_lt_zero_of_forall_lt_zero hint hss_neg have h_eval : f.eval 0 = f.leadingCoeff * (rs.map (0 - ·)).prod := by - rw [eval_eq_leadingCoeff_mul_prod_sub hf.2 0, ← hrs_eq] + rw [Polynomial.Splits.eval_eq_prod_roots hf.2 0, ← hrs_eq] simp have hrs_drop_prod_pos : 0 < (rs.dropLast.map (0 - ·)).prod := list_prod_pos_of_forall_pos (by grind) @@ -211,9 +211,9 @@ theorem roots_nonpos_of_strictInterl_sameDegree_of_zero_root_of_left_roots_neg ∀ r, g.IsRoot r → r ≤ 0 := by obtain ⟨hf, hg, ss, rs, _, _, hss_eq, hrs_eq, hshape⟩ := hfg have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have halt : ListAlternates ss rs := by rcases hshape with ⟨_, hint⟩ | ⟨_, halt⟩ · lia @@ -248,9 +248,9 @@ theorem roots_neg_of_strictInterl_sameDegree_of_roots_neg {g f : ℝ[X]} ∀ r, g.IsRoot r → r < 0 := by obtain ⟨hg, hf, ss, rs, _, _, hss_eq, hrs_eq, hshape⟩ := hgf have hss_len : ss.length = g.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hg.2] have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] rcases hshape with ⟨_, hint⟩ | ⟨_, halt⟩ · lia · have hrs_neg : ∀ s ∈ rs, s < 0 := by diff --git a/RealRooted/Interlacing/OuterDifference.lean b/RealRooted/Interlacing/OuterDifference.lean index 8a94f1c98..e8c55990f 100644 --- a/RealRooted/Interlacing/OuterDifference.lean +++ b/RealRooted/Interlacing/OuterDifference.lean @@ -34,9 +34,9 @@ theorem StrictInterl.eq_of_sameDegree_of_leadingCoeff_eq_of_roots_sum_eq rcases hstrictInterl with ⟨hf, hg, ss, rs, _hss_sorted, _hrs_sorted, hss_eq, hrs_eq, hshape⟩ have hlen_ss : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hlen_rs : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have halt : ListAlternates ss rs := by simp_all have hlist : ss = rs := by apply list_eq_of_forall₂_le_of_sum_ge (listAlternates_forall₂_le halt) diff --git a/RealRooted/Interlacing/PencilPreserver.lean b/RealRooted/Interlacing/PencilPreserver.lean index 62bbb4e1b..5eebe1227 100644 --- a/RealRooted/Interlacing/PencilPreserver.lean +++ b/RealRooted/Interlacing/PencilPreserver.lean @@ -90,7 +90,7 @@ private lemma negativeSimple_shape_of_strictInterl have hrs_ne : rs ≠ [] := by intro hrs_nil have : p.natDegree = 0 := by - rw [← card_roots_of_splits hp_rr.2, ← hrs_eq, hrs_nil] + rw [← Polynomial.splits_iff_card_roots.mp hp_rr.2, ← hrs_eq, hrs_nil] simp have : f.natDegree + 1 = 0 := by lia simp at this diff --git a/RealRooted/Interlacing/RemainderCertificate.lean b/RealRooted/Interlacing/RemainderCertificate.lean index 2fd4a87fb..37322053d 100644 --- a/RealRooted/Interlacing/RemainderCertificate.lean +++ b/RealRooted/Interlacing/RemainderCertificate.lean @@ -218,7 +218,7 @@ private lemma roots_eq_of_list_roots {p : ℝ[X]} {xs : List ℝ} intro x hx exact (mem_roots hp).mpr (hroot x (by simpa using hx)) apply Multiset.eq_of_le_of_card_le hsub - rw [card_roots_of_splits hps, hcard] + rw [Polynomial.splits_iff_card_roots.mp hps, hcard] simp /-- Remainder certificates for an affine perturbation of a linear polynomial. -/ diff --git a/RealRooted/Interlacing/Residue.lean b/RealRooted/Interlacing/Residue.lean index 96a3c72bf..a655ac482 100644 --- a/RealRooted/Interlacing/Residue.lean +++ b/RealRooted/Interlacing/Residue.lean @@ -240,7 +240,7 @@ theorem eval_lagInterp_at_root {f g : ℝ[X]} (hnd : f.roots.Nodup) theorem lagInterp_degree_lt {f g : ℝ[X]} (hfs : f.Splits) (hnd : f.roots.Nodup) (h_deg₁ : 1 ≤ f.natDegree) : (lagInterp f g).degree < f.roots.toFinset.card := by - rw [Multiset.toFinset_card_of_nodup hnd, card_roots_of_splits hfs, lagInterp] + rw [Multiset.toFinset_card_of_nodup hnd, Polynomial.splits_iff_card_roots.mp hfs, lagInterp] apply lt_of_le_of_lt (Polynomial.degree_sum_le _ _) have : (⊥ : WithBot ℕ) < (f.natDegree : WithBot ℕ) := by simp rw [Finset.sup_lt_iff this] @@ -263,7 +263,7 @@ theorem lagInterp_eq_g {f g : ℝ[X]} (hfs : f.Splits) (hnd : f.roots.Nodup) (h_deg₁ : 1 ≤ f.natDegree) (hgdeg : g.degree < f.natDegree) : lagInterp f g = g := by have : f.roots.toFinset.card = f.natDegree := by - rw [Multiset.toFinset_card_of_nodup hnd, card_roots_of_splits hfs] + rw [Multiset.toFinset_card_of_nodup hnd, Polynomial.splits_iff_card_roots.mp hfs] have h_deg_lt : (lagInterp f g).degree < f.roots.toFinset.card := lagInterp_degree_lt hfs hnd h_deg₁ apply eq_of_degrees_lt_of_eval_finset_eq f.roots.toFinset h_deg_lt diff --git a/RealRooted/Interlacing/ResidueCriterion.lean b/RealRooted/Interlacing/ResidueCriterion.lean index 236999fc7..8eb079b28 100644 --- a/RealRooted/Interlacing/ResidueCriterion.lean +++ b/RealRooted/Interlacing/ResidueCriterion.lean @@ -228,7 +228,7 @@ theorem residueAuxiliary_interlaces have hroots_ne : f.roots ≠ 0 := by intro hzero have hcard : f.roots.card = f.natDegree := - card_roots_of_splits hgf.2.1.2 + Polynomial.splits_iff_card_roots.mp hgf.2.1.2 rw [hzero] at hcard simp at hcard lia diff --git a/RealRooted/Interlacing/Reversal.lean b/RealRooted/Interlacing/Reversal.lean index f43fd62c3..e9d20e170 100644 --- a/RealRooted/Interlacing/Reversal.lean +++ b/RealRooted/Interlacing/Reversal.lean @@ -68,17 +68,17 @@ lemma interlaces_reverse_of_roots_neg {g f : ℝ[X]} (h : Interlaces g f) have hg0 := coeff_zero_ne_of_roots_neg hgne hg have hfr' := Polynomial.roots_reverse_eq_map_inv hfs hf0 have hgr' := Polynomial.roots_reverse_eq_map_inv hgs hg0 - have hfrs := DegreeDropReversal.splits_reverse hfs - have hgrs := DegreeDropReversal.splits_reverse hgs + have hfrs := Polynomial.Splits.reverse hfs + have hgrs := Polynomial.Splits.reverse hgs have hnat : ∀ {p : ℝ[X]}, p.Splits → p.coeff 0 ≠ 0 → p.reverse.natDegree = p.natDegree := by intro p hp hp0 - rw [← card_roots_of_splits (DegreeDropReversal.splits_reverse hp), + rw [← Polynomial.splits_iff_card_roots.mp (Polynomial.Splits.reverse hp), Polynomial.roots_reverse_eq_map_inv hp hp0, - Multiset.card_map, card_roots_of_splits hp] + Multiset.card_map, Polynomial.splits_iff_card_roots.mp hp] have hrslen : rs.length = f.natDegree := by - rw [← card_roots_of_splits hfs, ← hfr, Multiset.coe_card] + rw [← Polynomial.splits_iff_card_roots.mp hfs, ← hfr, Multiset.coe_card] have hsslen : ss.length = g.natDegree := by - rw [← card_roots_of_splits hgs, ← hgsr, Multiset.coe_card] + rw [← Polynomial.splits_iff_card_roots.mp hgs, ← hgsr, Multiset.coe_card] refine ⟨⟨DegreeDropReversal.reverse_ne_zero_of_coeff_zero_ne hf0, hfrs⟩, ⟨DegreeDropReversal.reverse_ne_zero_of_coeff_zero_ne hg0, hgrs⟩, ?_, ⟨(rs.map Inv.inv).reverse, (ss.map Inv.inv).reverse, ?_, ?_, ?_, ?_, ?_⟩⟩ @@ -216,6 +216,6 @@ theorem splits_of_eq_reflect {P R : ℕ → ℝ[X]} {D₀ : ℕ} (hPR : ∀ n, P n = reflect (D₀ + n) (R n)) (hdeg : ∀ n, (R n).natDegree ≤ D₀ + n) (hR : ∀ n, (R n).Splits) (n : ℕ) : (P n).Splits := by rw [hPR] - exact DegreeDropReversal.splits_reflect_of_splits (hR n) (hdeg n) + exact Polynomial.Splits.reflect (hR n) (hdeg n) end RealRooted diff --git a/RealRooted/Interlacing/RootCountSigns.lean b/RealRooted/Interlacing/RootCountSigns.lean index 12096963d..20b93d553 100644 --- a/RealRooted/Interlacing/RootCountSigns.lean +++ b/RealRooted/Interlacing/RootCountSigns.lean @@ -75,7 +75,7 @@ theorem strictInterl_of_eval_mul_neg_one_pow_countP_neg {p F : ℝ[X]} have hrs_lt : rs.Pairwise (· < ·) := (hrs_le.and hrs_nodup).imp (fun h => lt_of_le_of_ne h.1 h.2) have hrs_len : rs.length = p.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hps] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hps] have hrs_ne : rs ≠ [] := by intro h rw [h] at hrs_len diff --git a/RealRooted/Interlacing/WindowInduction.lean b/RealRooted/Interlacing/WindowInduction.lean index 5a5df677e..3b83eccb2 100644 --- a/RealRooted/Interlacing/WindowInduction.lean +++ b/RealRooted/Interlacing/WindowInduction.lean @@ -241,11 +241,4 @@ theorem StrictInterl.add_mul_X_of_common_left {h u v : ℝ[X]} {c : ℝ} · simp simpa only [List.sum_cons, List.sum_nil, add_zero, mul_assoc] using hsum -/-- Lag insertion through multiplication by `X`, in the orientation used by -positive-lag window recurrences. -/ -theorem StrictInterl.insert_X_lag_of_nonneg {f g : ℝ[X]} - (h : StrictInterl f g) (hf : HasNonnegCoeffs f) (hg : HasNonnegCoeffs g) : - StrictInterl g (X * f) := - strictInterl_mul_X_of_strictInterl_of_nonneg h hf hg - end RealRooted diff --git a/RealRooted/IteratedDerivativeShift.lean b/RealRooted/IteratedDerivativeShift.lean index ec82590f6..0ac21e884 100644 --- a/RealRooted/IteratedDerivativeShift.lean +++ b/RealRooted/IteratedDerivativeShift.lean @@ -1109,7 +1109,7 @@ lemma deriv2_mul_lt_deriv_sq_at_non_root {p : ℝ[X]} {a : ℝ} (hp : p.Splits) have hq₀ : q ≠ 0 := by rintro rfl; simp_all -- Get a root r of q (exists since degree ≥ 1 and real-rooted) have hroots_pos : 0 < q.roots.card := by - rw [card_roots_of_splits hq_rr] + rw [Polynomial.splits_iff_card_roots.mp hq_rr] lia obtain ⟨r, hr⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hr_root : q.IsRoot r := (mem_roots hq₀).mp hr diff --git a/RealRooted/Jacobi/Markoff.lean b/RealRooted/Jacobi/Markoff.lean index fffcbfc8e..fe0517eb8 100644 --- a/RealRooted/Jacobi/Markoff.lean +++ b/RealRooted/Jacobi/Markoff.lean @@ -828,7 +828,7 @@ theorem shiftedJacobiMonic_roots_sort_length (n : ℕ) {α β : ℝ} (hα : -1 < α) (hβ : -1 < β) : ((shiftedJacobiMonic n α β).roots.sort (· ≤ ·)).length = n := by rw [Multiset.length_sort, - card_roots_of_splits (shiftedJacobiMonic_splits n hα hβ), + Polynomial.splits_iff_card_roots.mp (shiftedJacobiMonic_splits n hα hβ), natDegree_shiftedJacobiMonic n hα hβ] theorem shiftedJacobiMonicRoot_isRoot (n : ℕ) (i : Fin n) diff --git a/RealRooted/JacobiDeformation/ImageProduct.lean b/RealRooted/JacobiDeformation/ImageProduct.lean index 537f3fb68..14fba0850 100644 --- a/RealRooted/JacobiDeformation/ImageProduct.lean +++ b/RealRooted/JacobiDeformation/ImageProduct.lean @@ -63,7 +63,7 @@ theorem imageProduct_natDegree {m : ℕ} (U V : ℝ) (x : Fin m → ℝ) : (imageProduct U V x).natDegree = m := by calc (imageProduct U V x).natDegree = (imageProduct U V x).roots.card := - (card_roots_of_splits (imageProduct_splits U V x)).symm + (Polynomial.splits_iff_card_roots.mp (imageProduct_splits U V x)).symm _ = m := by rw [roots_imageProduct, Multiset.card_map]; simp /-- Distinct interior nodes give image-product root multiplicity at most two, diff --git a/RealRooted/JacobiDeformation/Strict.lean b/RealRooted/JacobiDeformation/Strict.lean index e4b2c97d1..c35611c4c 100644 --- a/RealRooted/JacobiDeformation/Strict.lean +++ b/RealRooted/JacobiDeformation/Strict.lean @@ -120,7 +120,7 @@ theorem roots_card_polynomial_strict (hc : 0 < c) (hd : 0 < d) (hU : 0 < U) (hV : 0 < V) (hδ : 0 < δ) (hδ1 : δ < 1) : (polynomial m δ c d U V).roots.card = m := by - rw [card_roots_of_splits + rw [Polynomial.splits_iff_card_roots.mp (polynomial_strict_splits_simple_roots_neg hm hc hd hU hV hδ hδ1).1, natDegree_polynomial] diff --git a/RealRooted/JensenPencilContraction.lean b/RealRooted/JensenPencilContraction.lean index 1486d42d8..7bcd256ad 100644 --- a/RealRooted/JensenPencilContraction.lean +++ b/RealRooted/JensenPencilContraction.lean @@ -221,8 +221,8 @@ private theorem compatible_jensen_output_of_translate_core C b * (X * schurSzegoComp d (B.comp (X + C eps)) (p.comp (X + C eps)))) := by apply IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits - ((nonnegCoeffs_C_mul ha hUA.hasNonnegCoeffs).add - (nonnegCoeffs_C_mul hb hVB.hasNonnegCoeffs)) + ((hasNonnegCoeffs_C_mul ha hUA.hasNonnegCoeffs).add + (hasNonnegCoeffs_C_mul hb hVB.hasNonnegCoeffs)) rcases hcore heps a b ha hb with hzero | hsplits · exact Or.inl hzero · exact Or.inr hsplits.2 diff --git a/RealRooted/JensenPencilPositiveContraction.lean b/RealRooted/JensenPencilPositiveContraction.lean index 0fff22b75..069af3b8e 100644 --- a/RealRooted/JensenPencilPositiveContraction.lean +++ b/RealRooted/JensenPencilPositiveContraction.lean @@ -111,7 +111,7 @@ private theorem card_roots_monicSignedReciprocal_filter_ge_of_nonpos {s : ℝ} (hs : s ≤ 0) : ((monicSignedReciprocal d F).roots.filter (s ≤ ·)).card = d := by rw [roots_monicSignedReciprocal hF0, Multiset.filter_eq_self.mpr] - · rw [card_roots_of_splits + · rw [Polynomial.splits_iff_card_roots.mp (signedReciprocal_splits_of_splits hFdeg (hF.2.1.resolve_left (by intro h @@ -152,7 +152,7 @@ private theorem rootCount_band_monicSignedReciprocal · have hPAcard : (A.roots.filter (-s⁻¹ ≤ ·)).card ≤ d := (Multiset.card_le_card (Multiset.filter_le _ _)).trans (by - rw [card_roots_of_splits + rw [Polynomial.splits_iff_card_roots.mp (hA.2.1.resolve_left (by intro h subst A diff --git a/RealRooted/Kurtz.lean b/RealRooted/Kurtz.lean index 62aaf71de..e424533e2 100644 --- a/RealRooted/Kurtz.lean +++ b/RealRooted/Kurtz.lean @@ -463,7 +463,7 @@ theorem coefficient_criterion_card_roots {p : ℝ[X]} have : s.card + 1 = p.natDegree := by have : 1 ≤ n := (Nat.le_succ 1).trans (hn ▸ hdeg) rw [hs_card, Nat.sub_add_cancel this, hn] - exact card_roots_of_splits (roots_card_of_sub_pred hpne hs_le this) + exact Polynomial.splits_iff_card_roots.mp (roots_card_of_sub_pred hpne hs_le this) /-- Kurtz's sufficient condition: positive coefficients and the strict Hutchinson--Kurtz log-concavity inequalities imply real-rootedness. -/ @@ -472,7 +472,7 @@ theorem coefficient_criterion {p : ℝ[X]} (hpos : PositiveCoeffsUpToDegree p) (hineq : KurtzStrictInequalities p) : p.Splits := - splits_of_card_roots (coefficient_criterion_card_roots hdeg hpos hineq) + Polynomial.splits_iff_card_roots.mpr (coefficient_criterion_card_roots hdeg hpos hineq) end Kurtz end RealRooted diff --git a/RealRooted/Linear.lean b/RealRooted/Linear.lean index 3a3c72af1..67e0731e7 100644 --- a/RealRooted/Linear.lean +++ b/RealRooted/Linear.lean @@ -93,18 +93,6 @@ lemma isRealRooted_X_mul_of_isRealRooted {f : ℝ[X]} (hf : f ≠ 0 ∧ f.Splits X * f ≠ 0 ∧ (X * f).Splits := isRealRooted_X_mul hf.1 hf.2 -/-- If `p` has zero constant coefficient, splitting of `p.divX` gives splitting -of `p` by restoring the common factor `X`. -/ -lemma splits_of_divX_splits_of_coeff_zero {p : ℝ[X]} - (hp_pos : HasPosLeadingCoeff p) (h0 : p.coeff 0 = 0) - (hdiv : p.divX.Splits) : - p.Splits := by - have hX : X * p.divX = p := by simpa [h0] using Polynomial.X_mul_divX_add p - have _ := hp_pos.ne_zero - rw [← hX] - have hX_splits : (X : ℝ[X]).Splits := by simp - exact hX_splits.mul hdiv - lemma isRealRooted_X : ((X : ℝ[X]) ≠ 0 ∧ (X : ℝ[X]).Splits) := by simp /-- Orientation sanity check for the local `StrictInterl` convention on linear factors. @@ -120,8 +108,8 @@ lemma StrictInterl.X_add_C_iff {a b : ℝ} : simpa using hsum · intro hab refine ⟨?_, ?_, [(-b)], [(-a)], by simp, by simp, by simp, by simp, ?_⟩ - · simpa [sub_eq_add_neg] using isRealRooted_X_sub_C (-b) - · simpa [sub_eq_add_neg] using isRealRooted_X_sub_C (-a) + · simpa [sub_eq_add_neg] using X_sub_C_ne_zero (-b : ℝ) + · simpa [sub_eq_add_neg] using X_sub_C_ne_zero (-a : ℝ) · exact Or.inr ⟨by simp, by simpa [ListAlternates, ListInterlaces] using hab⟩ /-- Orientation criterion for zero-aware proper position of linear factors. -/ @@ -149,22 +137,10 @@ lemma isRealRooted_of_X_mul {f : ℝ[X]} f ≠ 0 ∧ f.Splits := by simp_all -/-- A root of a divisor is a root of the dividend. -/ -lemma IsRoot.of_dvd {p q : ℝ[X]} (hpq : p ∣ q) {x : ℝ} (hx : p.IsRoot x) : - q.IsRoot x := by - rcases hpq with ⟨r, rfl⟩ - simp_all - /-- A common root of two polynomials is also a root of their sum. -/ lemma IsRoot.add {p q : ℝ[X]} {x : ℝ} (hp : p.IsRoot x) (hq : q.IsRoot x) : (p + q).IsRoot x := by simp_all -/-- A nonunit real-rooted polynomial has a real root. -/ -lemma exists_isRoot_of_isRealRooted_of_not_isUnit {p : ℝ[X]} (hp_ne : p ≠ 0) - (hp_splits : p.Splits) (hu : ¬ IsUnit p) : ∃ r : ℝ, p.IsRoot r := by - have hdeg := degree_pos_of_ne_zero_of_nonunit hp_ne hu - simpa [Polynomial.IsRoot.def] using hp_splits.exists_eval_eq_zero hdeg.ne' - /-- If two real-rooted polynomials have no common real root, then they are coprime. -/ lemma isCoprime_of_no_common_real_root_of_isRealRooted {f g : ℝ[X]} (hf_ne : f ≠ 0) (hf_splits : f.Splits) @@ -174,9 +150,12 @@ lemma isCoprime_of_no_common_real_root_of_isRealRooted {f g : ℝ[X]} · lia · intro z hz_nonunit hz0 hzf hzg have hz_notunit : ¬ IsUnit z := by simp_all - have hz_rr : (z ≠ 0 ∧ z.Splits) := isRealRooted_of_dvd hf_ne hf_splits hz0 hzf - obtain ⟨r, hzr⟩ := exists_isRoot_of_isRealRooted_of_not_isUnit hz_rr.1 hz_rr.2 hz_notunit - exact hno r (IsRoot.of_dvd hzf hzr) (IsRoot.of_dvd hzg hzr) + have hz_rr : z ≠ 0 ∧ z.Splits := + ⟨hz0, hf_splits.of_dvd hf_ne hzf⟩ + obtain ⟨r, hzr⟩ : ∃ r : ℝ, z.IsRoot r := by + simpa [Polynomial.IsRoot.def] using hz_rr.2.exists_eval_eq_zero + (degree_pos_of_ne_zero_of_nonunit hz_rr.1 hz_notunit).ne' + exact hno r (hzr.dvd hzf) (hzr.dvd hzg) /-- Any nonzero degree-1 polynomial is real-rooted. -/ lemma isRealRooted_of_degree_one {p : ℝ[X]} (hp : p.natDegree = 1) : (p ≠ 0 ∧ p.Splits) := by @@ -191,7 +170,9 @@ lemma isRealRooted_of_natDegree_le_one {p : ℝ[X]} lemma interlaces_one_linear {p : ℝ[X]} (hp_deg : p.natDegree = 1) : Interlaces (1 : ℝ[X]) p := by have h1_rr : ((1 : ℝ[X]) ≠ 0 ∧ (1 : ℝ[X]).Splits) := by simp - have hp_rr : (p ≠ 0 ∧ p.Splits) := isRealRooted_of_degree_one hp_deg + have hp_rr : p ≠ 0 ∧ p.Splits := by + refine ⟨ne_zero_of_natDegree_gt (n := 0) ?_, Splits.of_natDegree_eq_one hp_deg⟩ + lia have hp_deg' : p.degree = 1 := by simpa [hp_deg] using degree_eq_natDegree hp_rr.1 refine ⟨hp_rr, h1_rr, by simp [Polynomial.natDegree_one, hp_deg], ?_⟩ refine ⟨[-(p.coeff 1)⁻¹ * p.coeff 0], [], by simp, by simp, ?_, by simp, @@ -284,35 +265,33 @@ private lemma listAlternates_reverse_map_one_sub {ss rs : List ℝ} intro a b hab linarith) -lemma roots_comp_one_sub_X (p : ℝ[X]) : +private lemma roots_comp_one_sub_X (p : ℝ[X]) : (p.comp (1 - X)).roots = p.roots.map (1 - ·) := by simpa [sub_eq_add_neg, add_comm, add_left_comm, add_assoc] using Polynomial.roots_comp_C_mul_X_add_C p (-1) 1 isUnit_neg_one -lemma isRealRooted_comp_one_sub_X - {p : ℝ[X]} (hp_ne : p ≠ 0) (hp_splits : p.Splits) : - (p.comp (1 - X) ≠ 0 ∧ (p.comp (1 - X)).Splits) := by - refine ⟨?_, hp_splits.comp_of_natDegree_le_one - ((natDegree_sub_le (1 : ℝ[X]) X).trans (by simp))⟩ - rw [Ne, Polynomial.comp_eq_zero_iff] - simp [hp_ne] - /-- Reflection about `1 / 2` reverses same-degree proper position. -/ lemma StrictInterl.comp_one_sub_X_of_natDegree_eq {f g : ℝ[X]} (h : StrictInterl f g) (hdeg : f.natDegree = g.natDegree) : StrictInterl (g.comp (1 - X)) (f.comp (1 - X)) := by rcases h with ⟨hf, hg, ss, rs, hss, hrs, hss_eq, hrs_eq, hshape⟩ have hlen : ss.length = rs.length := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2, - hdeg, ← card_roots_of_splits hg.2, ← hrs_eq, Multiset.coe_card] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2, + hdeg, ← Polynomial.splits_iff_card_roots.mp hg.2, ← hrs_eq, Multiset.coe_card] obtain ⟨_, halt⟩ := hshape.resolve_left (by simp_all) have halt' := listAlternates_reverse_map_one_sub hlen halt have hinter : List.Interleaves (· ≤ ·) (ss.reverse.map (1 - ·)) (rs.reverse.map (1 - ·)) := interleaves_of_listAlternates_of_length (by simp [hlen]) halt' - refine ⟨isRealRooted_comp_one_sub_X hg.1 hg.2, - isRealRooted_comp_one_sub_X hf.1 hf.2, + have hcomp : ∀ {p : ℝ[X]}, p ≠ 0 → p.Splits → + p.comp (1 - X) ≠ 0 ∧ (p.comp (1 - X)).Splits := by + intro p hp_ne hp_splits + refine ⟨?_, hp_splits.comp_of_natDegree_le_one + ((natDegree_sub_le (1 : ℝ[X]) X).trans (by simp))⟩ + rw [Ne, Polynomial.comp_eq_zero_iff] + simp [hp_ne] + refine ⟨hcomp hg.1 hg.2, hcomp hf.1 hf.2, rs.reverse.map (1 - ·), ss.reverse.map (1 - ·), hinter.pairwise_right, hinter.pairwise_left, ?_, ?_, Or.inr ⟨?_, halt'⟩⟩ · rw [roots_comp_one_sub_X, ← hrs_eq] @@ -326,7 +305,11 @@ so the relative order is unchanged. -/ lemma StrictInterl.comp_X_add_C {f g : ℝ[X]} (h : StrictInterl f g) (r : ℝ) : StrictInterl (f.comp (X + C r)) (g.comp (X + C r)) := by rcases h with ⟨hf, hg, ss, rs, hss, hrs, hss_eq, hrs_eq, hcase⟩ - refine ⟨isRealRooted_comp_X_add_C hf.1 hf.2 r, isRealRooted_comp_X_add_C hg.1 hg.2 r, + have hfcomp : f.comp (X + C r) ≠ 0 ∧ (f.comp (X + C r)).Splits := + ⟨comp_X_add_C_ne_zero_iff.mpr hf.1, hf.2.comp_X_add_C r⟩ + have hgcomp : g.comp (X + C r) ≠ 0 ∧ (g.comp (X + C r)).Splits := + ⟨comp_X_add_C_ne_zero_iff.mpr hg.1, hg.2.comp_X_add_C r⟩ + refine ⟨hfcomp, hgcomp, ss.map (· - r), rs.map (· - r), ?_, ?_, ?_, ?_, ?_⟩ · grind · grind @@ -346,6 +329,12 @@ lemma StrictInterl.comp_C_mul_X {f g : ℝ[X]} (h : StrictInterl f g) rcases h with ⟨hf, hg, ss, rs, _, _, hss_eq, hrs_eq, hcase⟩ have ha_ne : a ≠ 0 := ne_of_gt ha have ha_unit : IsUnit a := isUnit_iff_ne_zero.mpr ha_ne + have hfcomp : f.comp (C a * X) ≠ 0 ∧ (f.comp (C a * X)).Splits := + ⟨mt (comp_C_mul_X_eq_zero_iff (by simp [ha_ne])).mp hf.1, + hf.2.comp_of_natDegree_le_one (by simp [ha_ne])⟩ + have hgcomp : g.comp (C a * X) ≠ 0 ∧ (g.comp (C a * X)).Splits := + ⟨mt (comp_C_mul_X_eq_zero_iff (by simp [ha_ne])).mp hg.1, + hg.2.comp_of_natDegree_le_one (by simp [ha_ne])⟩ have hmono : ∀ {x y : ℝ}, x ≤ y → a⁻¹ * x ≤ a⁻¹ * y := by exact fun {_ _} hxy => mul_le_mul_of_nonneg_left hxy (inv_nonneg.mpr ha.le) have hroots_f : @@ -366,8 +355,7 @@ lemma StrictInterl.comp_C_mul_X {f g : ℝ[X]} (h : StrictInterl f g) (ss.map (a⁻¹ * ·)) (rs.map (a⁻¹ * ·)) := (interleaves_of_listInterlaces_of_length hlen hinterlaces).map (a⁻¹ * ·) @hmono - refine ⟨isRealRooted_comp_C_mul_X hf.1 hf.2 ha_ne, - isRealRooted_comp_C_mul_X hg.1 hg.2 ha_ne, + refine ⟨hfcomp, hgcomp, ss.map (a⁻¹ * ·), rs.map (a⁻¹ * ·), hinter.pairwise_left, hinter.pairwise_right, hroots_f, hroots_g, Or.inl ⟨by simpa using hlen, ?_⟩⟩ @@ -377,8 +365,7 @@ lemma StrictInterl.comp_C_mul_X {f g : ℝ[X]} (h : StrictInterl f g) (rs.map (a⁻¹ * ·)) (ss.map (a⁻¹ * ·)) := (interleaves_of_listAlternates_of_length hlen halternates).map (a⁻¹ * ·) @hmono - refine ⟨isRealRooted_comp_C_mul_X hf.1 hf.2 ha_ne, - isRealRooted_comp_C_mul_X hg.1 hg.2 ha_ne, + refine ⟨hfcomp, hgcomp, ss.map (a⁻¹ * ·), rs.map (a⁻¹ * ·), hinter.pairwise_right, hinter.pairwise_left, hroots_f, hroots_g, Or.inr ⟨by simpa using hlen, ?_⟩⟩ @@ -467,6 +454,8 @@ lemma natDegree_add_eq_of_same_natDegree_of_posLeadingCoeff {p q : ℝ[X]} /-- If the right summand has strictly larger degree and positive leading coefficient, then the sum keeps that degree. -/ +@[deprecated Polynomial.natDegree_add_eq_right_of_natDegree_lt +typeChanged + (since := "2026-10-21")] lemma natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff {p q : ℝ[X]} (hdeg : p.natDegree < q.natDegree) (hq_pos : HasPosLeadingCoeff q) : (p + q).natDegree = q.natDegree := by @@ -475,6 +464,8 @@ lemma natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff {p q : ℝ[X]} /-- If the left summand has strictly larger degree and positive leading coefficient, then the sum keeps that degree. -/ +@[deprecated Polynomial.natDegree_add_eq_left_of_natDegree_lt +typeChanged + (since := "2026-10-21")] lemma natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff {p q : ℝ[X]} (hdeg : q.natDegree < p.natDegree) (hp_pos : HasPosLeadingCoeff p) : (p + q).natDegree = p.natDegree := by diff --git a/RealRooted/LinearPowerFamily.lean b/RealRooted/LinearPowerFamily.lean index 831d1f7e2..d16bb7bfd 100644 --- a/RealRooted/LinearPowerFamily.lean +++ b/RealRooted/LinearPowerFamily.lean @@ -45,9 +45,8 @@ theorem strictInterl_X_pow_mul_both_of_strictInterl_nonneg {f g : ℝ[X]} (hasNonnegCoeffs_X.pow n).mul hfnn have hright_nonneg : HasNonnegCoeffs (X ^ n * g) := (hasNonnegCoeffs_X.pow n).mul hgnn - have hnext := ih.mul_X_both_of_roots_nonpos - (roots_nonpos_of_hasNonnegCoeffs hleft_nonneg) - (roots_nonpos_of_hasNonnegCoeffs hright_nonneg) + have hnext : StrictInterl (X * (X ^ n * f)) (X * (X ^ n * g)) := by + simpa using ih.mul_X_sub_C_both 0 simpa [pow_succ', mul_assoc] using hnext /-- A reverse strictly interlacing pair with nonnegative coefficients remains in diff --git a/RealRooted/LiuOppositeSigns/PositiveSplitPair.lean b/RealRooted/LiuOppositeSigns/PositiveSplitPair.lean index 9fe1c2c33..7fe862e42 100644 --- a/RealRooted/LiuOppositeSigns/PositiveSplitPair.lean +++ b/RealRooted/LiuOppositeSigns/PositiveSplitPair.lean @@ -18,7 +18,7 @@ lemma exists_linear_factor_of_splits_natDegree_one {p : ℝ[X]} (hp_split : p.Splits) (hpdeg : p.natDegree = 1) : ∃ a : ℝ, p.roots = {a} ∧ p = C p.leadingCoeff * (X - C a) := by obtain ⟨a, ha⟩ : ∃ a : ℝ, p.roots = {a} := - Multiset.card_eq_one.mp (by rw [card_roots_of_splits hp_split, hpdeg]) + Multiset.card_eq_one.mp (by rw [Polynomial.splits_iff_card_roots.mp hp_split, hpdeg]) refine ⟨a, ha, ?_⟩ have hprod := hp_split.eq_prod_roots rw [ha] at hprod diff --git a/RealRooted/LiuOppositeSigns/PositiveSplitRootCount.lean b/RealRooted/LiuOppositeSigns/PositiveSplitRootCount.lean index 9ab4a08a5..1f7bb3b0f 100644 --- a/RealRooted/LiuOppositeSigns/PositiveSplitRootCount.lean +++ b/RealRooted/LiuOppositeSigns/PositiveSplitRootCount.lean @@ -208,8 +208,8 @@ theorem posLeadingCoeff_and_natDegree_X_mul_sub_C_mul_of_right_natDegree_le hasPosLeadingCoeff_add_of_natDegree_lt_left (p := X * p) (q := -(C μ * q)) hnegC_deg_lt h.left_pos.X_mul · simpa [hXp_deg, sub_eq_add_neg] using - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff - (p := X * p) (q := -(C μ * q)) hnegC_deg_lt h.left_pos.X_mul + Polynomial.natDegree_add_eq_left_of_natDegree_lt + (p := X * p) (q := -(C μ * q)) hnegC_deg_lt theorem rootCountAbove_bounds_of_nonRoot {p q : ℝ[X]} (h : PositiveSplitRootCountPair p q) {x : ℝ} @@ -244,7 +244,7 @@ theorem left_natDegree_add_card_right_roots_filter_lt_le_right_natDegree_add_one have hp_count : rootCountAtOrAbove p a = p.natDegree := by have hfilter : p.roots.filter (fun r => a ≤ r) = p.roots := Multiset.filter_eq_self.mpr hroots_ge - simp [rootCountAtOrAbove, hfilter, card_roots_of_splits h.left_splits] + simp [rootCountAtOrAbove, hfilter, Polynomial.splits_iff_card_roots.mp h.left_splits] have hpart : lower + upper = q.natDegree := by have hcard := congrArg Multiset.card (Multiset.filter_add_not (p := fun r : ℝ => r < a) q.roots) @@ -254,7 +254,8 @@ theorem left_natDegree_add_card_right_roots_filter_lt_le_right_natDegree_add_one intro r _hr simp [not_lt] rw [Multiset.card_add] at hcard - simpa [lower, upper, rootCountAtOrAbove, hnot, card_roots_of_splits h.right_splits] + simpa [lower, upper, rootCountAtOrAbove, hnot, + Polynomial.splits_iff_card_roots.mp h.right_splits] using hcard have hbound : ((p.natDegree : ℤ) - upper) ≤ 1 := by simpa [hp_count, upper] using (h.count.bounds a).1 diff --git a/RealRooted/LiuOppositeSigns/RootCount.lean b/RealRooted/LiuOppositeSigns/RootCount.lean index 9ecc3e863..2bed77bd7 100644 --- a/RealRooted/LiuOppositeSigns/RootCount.lean +++ b/RealRooted/LiuOppositeSigns/RootCount.lean @@ -143,8 +143,8 @@ theorem RootCountCompatible.natDegree_abs_sub_le_one {p q : ℝ[X]} have hq_count : rootCountAtOrAbove q x = q.roots.card := rootCountAtOrAbove_eq_card_of_forall_le_roots hqx have hgap := h x - rw [hp_count, hq_count, card_roots_of_splits hp_splits, - card_roots_of_splits hq_splits] at hgap + rw [hp_count, hq_count, Polynomial.splits_iff_card_roots.mp hp_splits, + Polynomial.splits_iff_card_roots.mp hq_splits] at hgap exact hgap theorem rootCountAtOrAbove_le_natDegree_of_splits {p : ℝ[X]} @@ -153,7 +153,7 @@ theorem rootCountAtOrAbove_le_natDegree_of_splits {p : ℝ[X]} have hfilter_le : (p.roots.filter (fun r => x ≤ r)).card ≤ p.roots.card := Multiset.card_le_card (Multiset.filter_le (fun r => x ≤ r) p.roots) - simpa [rootCountAtOrAbove, card_roots_of_splits hp_splits] using hfilter_le + simpa [rootCountAtOrAbove, Polynomial.splits_iff_card_roots.mp hp_splits] using hfilter_le theorem rootCountAtOrAbove_eq_zero_of_splits_natDegree_eq_zero {p : ℝ[X]} (hp_splits : p.Splits) (hpdeg : p.natDegree = 0) (x : ℝ) : diff --git a/RealRooted/LiuOppositeSigns/RootCountClosure.lean b/RealRooted/LiuOppositeSigns/RootCountClosure.lean index 35e82d522..fefcf8464 100644 --- a/RealRooted/LiuOppositeSigns/RootCountClosure.lean +++ b/RealRooted/LiuOppositeSigns/RootCountClosure.lean @@ -415,14 +415,14 @@ theorem LeftRootCountBranch.of_forall_pos_exists_close hff', hgg', hbranch'⟩ := hclose 1 zero_lt_one have hf_degree : f'.natDegree = f.natDegree := by calc - f'.natDegree = f'.roots.card := (card_roots_of_splits hf'_split).symm + f'.natDegree = f'.roots.card := (Polynomial.splits_iff_card_roots.mp hf'_split).symm _ = f.roots.card := (Multiset.card_eq_card_of_rel hff').symm - _ = f.natDegree := card_roots_of_splits hf + _ = f.natDegree := Polynomial.splits_iff_card_roots.mp hf have hg_degree : g'.natDegree = g.natDegree := by calc - g'.natDegree = g'.roots.card := (card_roots_of_splits hg'_split).symm + g'.natDegree = g'.roots.card := (Polynomial.splits_iff_card_roots.mp hg'_split).symm _ = g.roots.card := (Multiset.card_eq_card_of_rel hgg').symm - _ = g.natDegree := card_roots_of_splits hg + _ = g.natDegree := Polynomial.splits_iff_card_roots.mp hg have hdegrees := hbranch'.natDegree_eq_or_eq_succ_or_eq_succ_succ hf'_ne hf'_split hg'_split diff --git a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/GapCounts.lean b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/GapCounts.lean index 2a08951fc..127f70a2a 100644 --- a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/GapCounts.lean +++ b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/GapCounts.lean @@ -280,7 +280,7 @@ theorem hpair.left_pos.ne_zero hpair.right_pos.ne_zero huv_lt hp_no (hno v hv) rw [Nat.min_eq_right hgap_le_two] have hq_part : lowerTail + plainGapSum + upperTail = q.natDegree := by - rw [← card_roots_of_splits hpair.right_splits] + rw [← Polynomial.splits_iff_card_roots.mp hpair.right_splits] simpa [lowerTail, plainGapSum, upperTail, gaps] using hpartition rw [← hq_part] exact Nat.add_le_add (Nat.add_le_add le_rfl hplain_le_min) le_rfl @@ -343,7 +343,7 @@ theorem PositiveSplitRootCountPair.card_right_roots_lt_head_le_card_xSub_le simp [not_lt] rw [Multiset.card_add] at hcard simpa [lower, upper, rootCountAtOrAbove, hnot, - card_roots_of_splits hpair.right_splits] using hcard + Polynomial.splits_iff_card_roots.mp hpair.right_splits] using hcard have hP_data := hpair.posLeadingCoeff_and_natDegree_X_mul_sub_C_mul_of_right_natDegree_le (by rw [hdeg]) μ @@ -421,7 +421,7 @@ theorem simp [not_lt] rw [Multiset.card_add] at hcard simpa [lower, upper, rootCountAtOrAbove, hnot, - card_roots_of_splits hpair.right_splits] using hcard + Polynomial.splits_iff_card_roots.mp hpair.right_splits] using hcard have hupper_eq : upper = (q.roots.filter (a < ·)).card := by simpa [upper] using @@ -512,7 +512,7 @@ theorem simp [not_lt] rw [Multiset.card_add] at hcard simpa [lower, upper, rootCountAtOrAbove, hnot, - card_roots_of_splits hpair.right_splits] using hcard + Polynomial.splits_iff_card_roots.mp hpair.right_splits] using hcard have hupper_eq : upper = (q.roots.filter (a < ·)).card := by simpa [upper] using @@ -696,7 +696,7 @@ theorem exact lt_of_le_of_ne har (Ne.symm hne) have hfilter : q.roots.filter (a < ·) = q.roots := Multiset.filter_eq_self.mpr hq_all_gt - simp [hfilter, card_roots_of_splits hpair.right_splits] + simp [hfilter, Polynomial.splits_iff_card_roots.mp hpair.right_splits] end LiuOppositeSigns end RealRooted diff --git a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/LeftSuccessor.lean b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/LeftSuccessor.lean index f3e5331c9..6a5762969 100644 --- a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/LeftSuccessor.lean +++ b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/LeftSuccessor.lean @@ -102,7 +102,7 @@ theorem PositiveSplitRootCountPair.xSub_splits_of_left_successor_nonneg_of_noCom rw [hdeg] exact Nat.succ_pos _ have hroots_pos : 0 < p.roots.card := by - simpa [card_roots_of_splits hpair.left_splits] using hp_nat_pos + simpa [Polynomial.splits_iff_card_roots.mp hpair.left_splits] using hp_nat_pos obtain ⟨x, hx⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hx_sort : x ∈ p.roots.toFinset.sort (· ≤ ·) := by rw [Finset.mem_sort, Multiset.mem_toFinset] diff --git a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/RightSuccessor.lean b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/RightSuccessor.lean index 4cd639bc2..39de4975f 100644 --- a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/RightSuccessor.lean +++ b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/RightSuccessor.lean @@ -258,7 +258,7 @@ theorem PositiveSplitRootCountPair.xSub_splits_of_right_successor_nonneg_of_noCo rw [hrs] at hx_sort simp at hx_sort have hpdeg_zero : p.natDegree = 0 := by - rw [← card_roots_of_splits hpair.left_splits, hroots_zero] + rw [← Polynomial.splits_iff_card_roots.mp hpair.left_splits, hroots_zero] simp have hqdeg_one : q.natDegree = 1 := by lia simpa using diff --git a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/SameDegree.lean b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/SameDegree.lean index 8fb550a53..1af5e9173 100644 --- a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/SameDegree.lean +++ b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/SameDegree.lean @@ -103,7 +103,7 @@ theorem PositiveSplitRootCountPair.xSub_splits_of_same_degree_nonneg_of_noCommon rw [hrs] at hx_sort simp at hx_sort have hpdeg_zero : p.natDegree = 0 := by - rw [← card_roots_of_splits hpair.left_splits, hroots_zero] + rw [← Polynomial.splits_iff_card_roots.mp hpair.left_splits, hroots_zero] simp have hqdeg_zero : q.natDegree = 0 := by lia simpa using diff --git a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/UpperTail.lean b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/UpperTail.lean index bde75321a..99e11b0dc 100644 --- a/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/UpperTail.lean +++ b/RealRooted/LiuOppositeSigns/XSub/IntervalRootCount/UpperTail.lean @@ -114,14 +114,14 @@ theorem (p := p) (q := -(C μ * q.divX)) hnegCdiv_deg_lt hpair.left_pos have hR_natDegree : R.natDegree = p.natDegree := by simpa [R, sub_eq_add_neg] using - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff - (p := p) (q := -(C μ * q.divX)) hnegCdiv_deg_lt hpair.left_pos + Polynomial.natDegree_add_eq_left_of_natDegree_lt + (p := p) (q := -(C μ * q.divX)) hnegCdiv_deg_lt have hp_nat_pos : 0 < p.natDegree := by have ha_mem : a ∈ p.roots := (Polynomial.mem_roots hpair.left_pos.ne_zero).mpr ha.isRoot have hcard_pos : 0 < p.roots.card := Multiset.card_pos_iff_exists_mem.mpr ⟨a, ha_mem⟩ - simpa [card_roots_of_splits hpair.left_splits] using hcard_pos + simpa [Polynomial.splits_iff_card_roots.mp hpair.left_splits] using hcard_pos have hR_nat_pos : 0 < R.natDegree := by simpa [hR_natDegree] using hp_nat_pos have hR_degree_pos : 0 < R.degree := Polynomial.natDegree_pos_iff_degree_pos.mp hR_nat_pos @@ -213,7 +213,7 @@ theorem (Polynomial.mem_roots hpair.left_pos.ne_zero).mpr ha.isRoot have hcard_pos : 0 < p.roots.card := Multiset.card_pos_iff_exists_mem.mpr ⟨a, ha_mem⟩ - simpa [card_roots_of_splits hpair.left_splits] using hcard_pos + simpa [Polynomial.splits_iff_card_roots.mp hpair.left_splits] using hcard_pos have hR_nat_pos : 0 < R.natDegree := by simpa [hR_natDegree] using hp_nat_pos have hR_degree_pos : 0 < R.degree := Polynomial.natDegree_pos_iff_degree_pos.mp hR_nat_pos diff --git a/RealRooted/MaWang/CountBounds.lean b/RealRooted/MaWang/CountBounds.lean index 735850b97..fba6ce4fb 100644 --- a/RealRooted/MaWang/CountBounds.lean +++ b/RealRooted/MaWang/CountBounds.lean @@ -19,7 +19,7 @@ points all lie to the right of the current left-hand point, and one of the remaining points after the next consumed root already lies before the next left-hand point. This is exactly the data needed to assemble an actual sorted right-hand root list into a weak `ListInterlaces` layout. -/ -theorem listInterlaces_of_drop_bounds : +private theorem listInterlaces_of_drop_bounds : ∀ {ss ts : List ℝ}, ss.Pairwise (· ≤ ·) → ts.Pairwise (· ≤ ·) → @@ -82,7 +82,7 @@ say that after consuming the first `pre.length` right-hand points, all remaining points lie to the right of the current left-hand point, and one of them already lies before the next left-hand point. This packages an actual sorted root list into a weak `ListAlternates` layout. -/ -theorem listAlternates_of_drop_bounds : +private theorem listAlternates_of_drop_bounds : ∀ {ss ts : List ℝ}, ss.Pairwise (· ≤ ·) → ts.Pairwise (· ≤ ·) → @@ -126,7 +126,7 @@ theorem listAlternates_of_drop_bounds : /-- If a sorted list has at most `k` entries strictly below `s`, then every entry in the `drop k` tail is `≥ s`. This is the count-to-tail bridge needed to feed actual sorted root lists into the `drop`-based layout lemmas above. -/ -lemma all_ge_of_countP_lt_drop +private lemma all_ge_of_countP_lt_drop {ts : List ℝ} (hts : ts.Pairwise (· ≤ ·)) {s : ℝ} {k : ℕ} (hcount : ts.countP (· < s) ≤ k) : ∀ u ∈ ts.drop k, s ≤ u := by @@ -157,7 +157,7 @@ lemma all_ge_of_countP_lt_drop /-- If a list has more than `k` entries `≤ s`, then some entry of the `drop k` tail is still `≤ s`. -/ -lemma exists_mem_drop_le_of_lt_countP +private lemma exists_mem_drop_le_of_lt_countP {ts : List ℝ} {s : ℝ} {k : ℕ} (hcount : k < ts.countP (· ≤ s)) : ∃ u, u ∈ ts.drop k ∧ u ≤ s := by @@ -181,7 +181,7 @@ right-hand list has: - more than `pre.length + 1` elements `≤` the next left-hand point, then the two lists satisfy the weak `ListInterlaces` layout. -/ -theorem listInterlaces_of_count_bounds +private theorem listInterlaces_of_count_bounds {ss ts : List ℝ} (hss : ss.Pairwise (· ≤ ·)) (hts : ts.Pairwise (· ≤ ·)) @@ -218,7 +218,7 @@ right-hand list has: - more than `pre.length` elements `≤` the next left-hand point, then the two lists satisfy the weak `ListAlternates` layout. -/ -theorem listAlternates_of_count_bounds +private theorem listAlternates_of_count_bounds {ss ts : List ℝ} (hss : ss.Pairwise (· ≤ ·)) (hts : ts.Pairwise (· ≤ ·)) @@ -263,9 +263,9 @@ theorem strictInterl_of_count_bounds_succ pre.length + 1 < ts.countP (· ≤ s₂)) : StrictInterl f F := by have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] have hts_len : ts.length = F.natDegree := by - rw [← Multiset.coe_card, hts_eq, card_roots_of_splits hF_splits] + rw [← Multiset.coe_card, hts_eq, Polynomial.splits_iff_card_roots.mp hF_splits] have hlen : rs.length + 1 = ts.length := by lia exact ⟨⟨hf_ne, hf_splits⟩, ⟨hF_ne, hF_splits⟩, rs, ts, hrs_sorted, hts_sorted, hrs_eq, hts_eq, @@ -291,9 +291,9 @@ theorem strictInterl_of_count_bounds_same pre.length < ts.countP (· ≤ s₂)) : StrictInterl f F := by have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] have hts_len : ts.length = F.natDegree := by - rw [← Multiset.coe_card, hts_eq, card_roots_of_splits hF_splits] + rw [← Multiset.coe_card, hts_eq, Polynomial.splits_iff_card_roots.mp hF_splits] have hlen : rs.length = ts.length := by lia exact ⟨⟨hf_ne, hf_splits⟩, ⟨hF_ne, hF_splits⟩, rs, ts, hrs_sorted, hts_sorted, hrs_eq, hts_eq, diff --git a/RealRooted/MaWang/StrictSigns/Assembly.lean b/RealRooted/MaWang/StrictSigns/Assembly.lean index ba1f02ede..2e6633c67 100644 --- a/RealRooted/MaWang/StrictSigns/Assembly.lean +++ b/RealRooted/MaWang/StrictSigns/Assembly.lean @@ -72,7 +72,7 @@ theorem interlaces_of_consecutive_signs_of_natDegree_lt (F := F) hrs_sorted (by grind) have hrs_len : rs.length = f.natDegree := by rw [show rs = f.roots.sort (· ≤ ·) by lia, Multiset.length_sort, - card_roots_of_splits hf_splits] + Polynomial.splits_iff_card_roots.mp hf_splits] have hus_sub : (↑us : Multiset ℝ) ≤ F.roots := by rw [Multiset.le_iff_subset (Multiset.coe_nodup.mpr (hus_pw.imp ne_of_lt))] intro x hx @@ -88,7 +88,7 @@ theorem interlaces_of_consecutive_signs_of_natDegree_lt apply Multiset.eq_of_le_of_card_le hus_sub simpa [Multiset.coe_card, hus_len_deg] using card_roots' F have hF : F ≠ 0 ∧ F.Splits := - ⟨hF_ne, splits_of_card_roots (by rw [← hus_eq, Multiset.coe_card, hus_len_deg])⟩ + ⟨hF_ne, Polynomial.splits_iff_card_roots.mpr (by rw [← hus_eq, Multiset.coe_card, hus_len_deg])⟩ exact ⟨⟨hf_ne, hf_splits⟩, hF, hdeg, rs, us, hrs_sorted, hus_pw.imp le_of_lt, hrs_eq, hus_eq, hus_int⟩ @@ -144,7 +144,7 @@ theorem interlaces_of_eval_mul_derivative_pos /-- If every element of the right-hand list is strictly above `a`, then so is every element of the interlacing left-hand list. -/ -lemma listInterlaces_all_gt_of_lowerBound : +private lemma listInterlaces_all_gt_of_lowerBound : ∀ {us rs : List ℝ}, ListInterlaces us rs → ∀ {a : ℝ}, (∀ r ∈ rs, a < r) → ∀ u ∈ us, a < u @@ -161,7 +161,7 @@ lemma listInterlaces_all_gt_of_lowerBound : /-- If every element of the right-hand list is strictly below `a`, then so is every element of the interlacing left-hand list. -/ -lemma listInterlaces_all_lt_of_upperBound : +private lemma listInterlaces_all_lt_of_upperBound : ∀ {us rs : List ℝ}, ListInterlaces us rs → ∀ {a : ℝ}, (∀ r ∈ rs, r < a) → ∀ u ∈ us, u < a @@ -322,7 +322,7 @@ lemma mul_neg_of_mul_neg_of_mul_neg {a b c d : ℝ} /-- If `ss` interlaces a nonempty sorted list `rs`, then adjoining one extra point `uR` to the right turns the tail of `rs` into a `ListInterlaces` witness against `ss ++ [uR]`. -/ -lemma listInterlaces_of_interlacing_append_right : +private lemma listInterlaces_of_interlacing_append_right : ∀ {ss rs : List ℝ}, rs ≠ [] → ListInterlaces ss rs → @@ -360,7 +360,7 @@ theorem strictInterl_same_of_strict_signs_of_right_root obtain ⟨us, hus_len, hus_int, hus_roots, hus_pw⟩ := exists_roots_strictly_interlacing_of_consecutive_signs (F := F) hrs_sorted hsign have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] obtain ⟨r, rs', rfl⟩ := List.exists_cons_of_ne_nil (by grind : rs ≠ []) have hall_us_lt_uR : ∀ u ∈ us, u < uR := listInterlaces_all_lt_of_upperBound hus_int huR_lt @@ -374,7 +374,7 @@ theorem strictInterl_same_of_strict_signs_of_right_root apply Multiset.eq_of_le_of_card_le hws_sub simpa [Multiset.coe_card, hws_len] using card_roots' F have hF : F ≠ 0 ∧ F.Splits := - ⟨hF_ne, splits_of_card_roots (by rw [← hws_eq, Multiset.coe_card, hws_len])⟩ + ⟨hF_ne, Polynomial.splits_iff_card_roots.mpr (by rw [← hws_eq, Multiset.coe_card, hws_len])⟩ have hws_sorted : (us ++ [uR]).Pairwise (· ≤ ·) := hws_pw.imp le_of_lt have hshape : ListAlternates (r :: rs') (us ++ [uR]) := by cases us with @@ -396,7 +396,7 @@ theorem strictInterl_same_of_strict_signs_of_right_root Or.inr ⟨hlen_shape, hshape⟩⟩ /-- Add one outer point on each side of a sorted interlacing layout. -/ -lemma listInterlaces_with_outer : +private lemma listInterlaces_with_outer : ∀ {us rs : List ℝ}, rs ≠ [] → rs.Pairwise (· ≤ ·) → @@ -427,7 +427,7 @@ lemma listInterlaces_with_outer : /-- Assemble a differ-by-1 `StrictInterl` statement from strict sign changes on a sorted root list together with one strict outer root on each side. -/ -theorem strictInterl_of_strict_signs_of_strict_outer_roots +private theorem strictInterl_of_strict_signs_of_strict_outer_roots {f F : ℝ[X]} {rs : List ℝ} (hf_ne : f ≠ 0) (hf_splits : f.Splits) (hF_ne : F ≠ 0) (hrs_sorted : rs.Pairwise (· ≤ ·)) @@ -446,7 +446,7 @@ theorem strictInterl_of_strict_signs_of_strict_outer_roots obtain ⟨us, hus_len, hus_int, hus_roots, hus_pw⟩ := exists_roots_strictly_interlacing_of_consecutive_signs (F := F) hrs_sorted hsign have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] obtain ⟨r, rs', rfl⟩ := List.exists_cons_of_ne_nil (by grind : rs ≠ []) have huL_lt_uR : uL < uR := lt_trans (huL_lt r (by simp)) (huR_lt r (by simp)) have huL_lt_all_us : ∀ u ∈ us, uL < u := @@ -470,7 +470,7 @@ theorem strictInterl_of_strict_signs_of_strict_outer_roots rw [Multiset.coe_card, hws_len] exact card_roots' F have hF : F ≠ 0 ∧ F.Splits := - ⟨hF_ne, splits_of_card_roots (by rw [← hws_eq, Multiset.coe_card, hws_len])⟩ + ⟨hF_ne, Polynomial.splits_iff_card_roots.mpr (by rw [← hws_eq, Multiset.coe_card, hws_len])⟩ have hws_sorted : (uL :: us ++ [uR]).Pairwise (· ≤ ·) := hws_pw.imp le_of_lt have hshape : ListInterlaces (r :: rs') (uL :: us ++ [uR]) := listInterlaces_with_outer (by simp) hrs_sorted hus_int diff --git a/RealRooted/MaWang/StrictSigns/RootSigns.lean b/RealRooted/MaWang/StrictSigns/RootSigns.lean index 78c2fec68..ecd8f4102 100644 --- a/RealRooted/MaWang/StrictSigns/RootSigns.lean +++ b/RealRooted/MaWang/StrictSigns/RootSigns.lean @@ -9,7 +9,7 @@ namespace RealRooted.MaWangInternal /-- Sign-normalization for a product of linear factors: multiplying by `(-1) ^ countP (s < ·)` flips exactly the negative factors and makes the product nonnegative. -/ -lemma nonneg_normalized_prod_sub_countP : +private lemma nonneg_normalized_prod_sub_countP : ∀ (ts : List ℝ) (s : ℝ), 0 ≤ (-1 : ℝ) ^ (ts.countP (s < ·)) * (ts.map (fun x => s - x)).prod | [], _ => by simp @@ -27,11 +27,11 @@ lemma nonneg_normalized_prod_sub_countP : /-- For a real-rooted polynomial with positive leading coefficient, the sign of `F.eval s` is controlled by the parity of the number of roots strictly to the right of `s`. -/ -lemma nonneg_normalized_eval_of_countP_gt +private lemma nonneg_normalized_eval_of_countP_gt {F : ℝ[X]} (hF_splits : F.Splits) (hF_pos : HasPosLeadingCoeff F) {ts : List ℝ} (hts_eq : (↑ts : Multiset ℝ) = F.roots) (s : ℝ) : 0 ≤ (-1 : ℝ) ^ (ts.countP (s < ·)) * F.eval s := by - rw [eval_eq_leadingCoeff_mul_prod_sub hF_splits s, ← hts_eq] + rw [Polynomial.Splits.eval_eq_prod_roots hF_splits s, ← hts_eq] change 0 ≤ (-1 : ℝ) ^ ts.countP (s < ·) * (F.leadingCoeff * (ts.map (fun x => s - x)).prod) convert mul_nonneg hF_pos.le (nonneg_normalized_prod_sub_countP ts s) using 1 @@ -65,7 +65,7 @@ lemma isRoot_of_eval_nonneg_of_odd_countP_gt /-- In an interlacing layout, every consecutive pair on the right-hand list has some left-hand element weakly between them. -/ -lemma exists_mem_between_of_listInterlaces_consecutive : +private lemma exists_mem_between_of_listInterlaces_consecutive : ∀ {ss rs pre : List ℝ} {r₁ r₂ : ℝ} {rest : List ℝ}, ListInterlaces ss rs → rs = pre ++ r₁ :: r₂ :: rest → @@ -162,7 +162,7 @@ lemma isRoot_of_mem_sorted_roots_eq /-- In a sorted interlacing layout, the polynomial-factor product has opposite-or-zero signs at any consecutive pair on the right-hand list. -/ -lemma listInterlaces_prod_mul_prod_nonpos_of_consecutive : +private lemma listInterlaces_prod_mul_prod_nonpos_of_consecutive : ∀ {ss rs pre : List ℝ} {r₁ r₂ : ℝ} {rest : List ℝ}, rs.Pairwise (· ≤ ·) → ListInterlaces ss rs → @@ -241,8 +241,8 @@ lemma eval_mul_eval_nonpos_of_interlacing_consecutive {g : ℝ[X]} (hint : ListInterlaces ss rs) (hEq : rs = pre ++ r₁ :: r₂ :: rest) : g.eval r₁ * g.eval r₂ ≤ 0 := by - rw [eval_eq_leadingCoeff_mul_prod_sub hg_splits r₁, - eval_eq_leadingCoeff_mul_prod_sub hg_splits r₂, ← hss_eq] + rw [Polynomial.Splits.eval_eq_prod_roots hg_splits r₁, + Polynomial.Splits.eval_eq_prod_roots hg_splits r₂, ← hss_eq] have hprod_nonpos : (ss.map (fun x => r₁ - x)).prod * (ss.map (fun x => r₂ - x)).prod ≤ 0 := listInterlaces_prod_mul_prod_nonpos_of_consecutive hrs_sorted hint hEq diff --git a/RealRooted/MaWang/Strong.lean b/RealRooted/MaWang/Strong.lean index 33a21d279..626a073ee 100644 --- a/RealRooted/MaWang/Strong.lean +++ b/RealRooted/MaWang/Strong.lean @@ -18,7 +18,7 @@ theorem strictInterl_of_interlaces_eval_mul_neg_succ {f g F : ℝ[X]} StrictInterl f F := by obtain ⟨hf, hg, hgdeg, rs, ss, hrs_sorted, hss_sorted, hrs_eq, hss_eq, hint⟩ := hgf have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hn : 1 ≤ rs.length := by lia have hrs_ne : rs ≠ [] := by grind obtain ⟨r₀, rs', rfl⟩ := List.exists_cons_of_ne_nil hrs_ne @@ -95,7 +95,7 @@ theorem strictInterl_of_interlaces_eval_mul_neg_same {f g F : ℝ[X]} StrictInterl f F := by obtain ⟨hf, hg, hgdeg, rs, ss, hrs_sorted, hss_sorted, hrs_eq, hss_eq, hint⟩ := hgf have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hn : 1 ≤ rs.length := by lia have hrs_ne : rs ≠ [] := by grind obtain ⟨r₀, rs', rfl⟩ := List.exists_cons_of_ne_nil hrs_ne @@ -177,7 +177,7 @@ lemma eval_mul_derivative_eq_of_isRoot {f u v : ℝ[X]} {r : ℝ} simp only [eval_add, eval_mul, hr.eq_zero, mul_zero, zero_add] ring -lemma eval_mul_right_eq_of_isRoot {f g a b : ℝ[X]} {r : ℝ} +private lemma eval_mul_right_eq_of_isRoot {f g a b : ℝ[X]} {r : ℝ} (hr : f.IsRoot r) : (a * f + b * g).eval r * g.eval r = b.eval r * (g.eval r) ^ 2 := by diff --git a/RealRooted/MaWang/Weak/Regularization.lean b/RealRooted/MaWang/Weak/Regularization.lean index b7ab40583..c6332be02 100644 --- a/RealRooted/MaWang/Weak/Regularization.lean +++ b/RealRooted/MaWang/Weak/Regularization.lean @@ -8,7 +8,7 @@ namespace RealRooted.MaWangInternal /-- Weak-sign Liu--Wang perturbation step: subtracting a small positive constant from the coefficient of `g` makes the root-sign condition strict, so the strict mixed theorem applies. -/ -theorem strictInterl_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common +private theorem strictInterl_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common {f g a b : ℝ[X]} (hgf : Interlaces g f) (hg_pos : HasPosLeadingCoeff g) @@ -41,7 +41,7 @@ theorem strictInterl_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common (hnat_Fδ.trans (by simpa [F] using hsucc)) hroot_sign /-- Real-rootedness for the perturbed weak-sign Liu--Wang combination. -/ -theorem isRealRooted_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common +private theorem isRealRooted_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common {f g a b : ℝ[X]} (hgf : Interlaces g f) (hg_pos : HasPosLeadingCoeff g) @@ -54,18 +54,6 @@ theorem isRealRooted_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common (((a * f + b * g) - C δ * g) ≠ 0 ∧ ((a * f + b * g) - C δ * g).Splits) := (strictInterl_sub_C_mul_of_interlaces_evalCoeff_nonpos_of_no_common hgf hg_pos hF_pos hdeg_lo hdeg_hi hno hb_nonpos hδ).2.1 -lemma mem_range_of_mem_aroots_of_isRealRooted {p : ℝ[X]} - (hp_splits : p.Splits) - {z : ℂ} (hz : z ∈ p.aroots ℂ) : - z ∈ (algebraMap ℝ ℂ).range := by - rw [← show p.roots.map (algebraMap ℝ ℂ) = p.aroots ℂ by - simpa [Polynomial.aroots_def] using - roots_map_of_injective_of_card_eq_natDegree - (p := p) (f := algebraMap ℝ ℂ) (algebraMap ℝ ℂ).injective - (card_roots_of_splits hp_splits)] at hz - rcases Multiset.mem_map.mp hz with ⟨x, _, rfl⟩ - simp - /-- If every positive perturbation `F - C δ * g` is real-rooted, then `F` is real-rooted as well. The interlacing hypothesis is only used to keep the degree and leading coefficient stable under the subtraction. -/ @@ -156,7 +144,8 @@ theorem isRealRooted_of_interlaces_sub_C_mul_of_forall_pos (IsAlgClosed.splits _) have hFδ_rr := hsub_rr hδ_pos have hqδ_rr : qδ ≠ 0 ∧ qδ.Splits := by simp_all [qδ] - rcases mem_range_of_mem_aroots_of_isRealRooted hqδ_rr.2 hw_mem with ⟨x, rfl⟩ + have hw_root : (qδ.map (algebraMap ℝ ℂ)).IsRoot w := by simp_all + rcases hqδ_rr.2.mem_range_of_isRoot hqδ_rr.1 hw_root with ⟨x, rfl⟩ have him_le : eps0 ≤ ‖z - x‖ := by unfold eps0 simpa using (Complex.abs_im_le_norm (z - x)) @@ -191,7 +180,7 @@ theorem isRealRooted_of_interlaces_sub_C_mul_of_forall_pos simp_all [-hF_eq] /-- Weak-sign Liu--Wang real-rootedness theorem in the no-common-roots regime. -/ -theorem isRealRooted_of_interlaces_evalCoeff_nonpos_of_no_common +private theorem isRealRooted_of_interlaces_evalCoeff_nonpos_of_no_common {f g a b : ℝ[X]} (hgf : Interlaces g f) (hg_pos : HasPosLeadingCoeff g) diff --git a/RealRooted/MaWang/Weak/Successor.lean b/RealRooted/MaWang/Weak/Successor.lean index 5fc4eb2f3..c5c79c0aa 100644 --- a/RealRooted/MaWang/Weak/Successor.lean +++ b/RealRooted/MaWang/Weak/Successor.lean @@ -18,10 +18,10 @@ private theorem strictInterl_of_interlaces_eval_mul_nonpos_of_no_common_aux have hts_eq : (↑ts : Multiset ℝ) = F.roots := Multiset.sort_eq .. have hts_sorted : ts.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hts_len : ts.length = F.natDegree := by rw [show ts = F.roots.sort (· ≤ ·) by lia, Multiset.length_sort, - card_roots_of_splits hF_splits] + Polynomial.splits_iff_card_roots.mp hF_splits] have hoff : ts.length = rs.length + off := by lia have hstrict : ∀ (pre : List ℝ) {r₁ r₂ : ℝ} {rest : List ℝ}, diff --git a/RealRooted/Mathlib/Algebra/Polynomial/Reverse.lean b/RealRooted/Mathlib/Algebra/Polynomial/Reverse.lean index f90b56bd3..daaf5445a 100644 --- a/RealRooted/Mathlib/Algebra/Polynomial/Reverse.lean +++ b/RealRooted/Mathlib/Algebra/Polynomial/Reverse.lean @@ -126,6 +126,76 @@ end CommRing variable {K : Type*} [Field K] +namespace Splits + +private theorem reverse_X_add_C (a : K) : + (X + C a).reverse.Splits := + Splits.of_natDegree_le_one <| + (reverse_natDegree_le (X + C a)).trans <| by simp + +/-- Reversal preserves splitting over a field. -/ +theorem reverse {p : K[X]} (h : p.Splits) : p.reverse.Splits := by + induction h using Submonoid.closure_induction with + | mem x hx => + rcases hx with ⟨a, rfl⟩ | ⟨a, rfl⟩ + · simp + · exact reverse_X_add_C a + | one => + exact Splits.of_natDegree_le_one <| + (reverse_natDegree_le (1 : K[X])).trans <| by simp + | mul x y _ _ ihx ihy => simp_all + +/-- Multiplying the reverse of a split polynomial by a power of `X` preserves +splitting. -/ +theorem X_pow_mul_reverse {p : K[X]} (h : p.Splits) (N : ℕ) : + (X ^ (N - p.natDegree) * p.reverse).Splits := + (Splits.X_pow (N - p.natDegree)).mul h.reverse + +end Splits + +/-- Reflecting at a degree bound factors through reversal and a power of `X`. -/ +theorem reflect_eq_X_pow_mul_reverse (p : K[X]) {N : ℕ} (hN : p.natDegree ≤ N) : + reflect N p = X ^ (N - p.natDegree) * p.reverse := by + obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le hN + induction k with + | zero => simp [Polynomial.reverse] + | succ k ih => + rw [Nat.add_succ, reflect_succ p (Nat.le_add_right _ _), + ih (Nat.le_add_right _ _), mul_assoc, ← commute_X, ← mul_assoc, + ← pow_succ] + rw [show p.natDegree + k - p.natDegree = k by lia, + show p.natDegree + k + 1 - p.natDegree = k + 1 by lia] + +namespace Splits + +/-- Reflection at any degree bound preserves splitting. -/ +theorem reflect {p : K[X]} (h : p.Splits) {N : ℕ} (hN : p.natDegree ≤ N) : + (reflect N p).Splits := by + simpa [reflect_eq_X_pow_mul_reverse p hN] using h.X_pow_mul_reverse N + +end Splits + +/-- At a valid degree bound, reflection preserves and reflects splitting. -/ +theorem splits_reflect_iff {p : K[X]} {N : ℕ} (hN : p.natDegree ≤ N) : + (reflect N p).Splits ↔ p.Splits := by + refine ⟨?_, fun h ↦ h.reflect hN⟩ + intro h + simpa using h.reflect <| + (natDegree_reflect_le (N := N) (p := p)).trans (max_eq_left hN).le + +/-- Reversal preserves and reflects splitting over a field. -/ +theorem splits_reverse_iff {p : K[X]} : p.reverse.Splits ↔ p.Splits := by + simpa [Polynomial.reverse] using + (splits_reflect_iff (p := p) (N := p.natDegree) le_rfl) + +namespace Splits + +/-- If the reverse splits, then the original polynomial splits. -/ +theorem of_reverse {p : K[X]} (h : p.reverse.Splits) : p.Splits := + splits_reverse_iff.mp h + +end Splits + section CharZero variable [CharZero K] {p : K[X]} {n : ℕ} diff --git a/RealRooted/MatrixInterlacing/AffinePair.lean b/RealRooted/MatrixInterlacing/AffinePair.lean index 90d981e83..071d628b8 100644 --- a/RealRooted/MatrixInterlacing/AffinePair.lean +++ b/RealRooted/MatrixInterlacing/AffinePair.lean @@ -182,9 +182,9 @@ lemma hasNonnegCoeffs_rowPairAffineSeq · have ha : HasNonnegCoeffs a := hrow₁_nonneg a (by simp) have hb : HasNonnegCoeffs b := hrow₂_nonneg b (by simp) have hsa : HasNonnegCoeffs (C s * (X * a)) := - nonnegCoeffs_C_mul hs ha.X_mul + hasNonnegCoeffs_C_mul hs ha.X_mul have hta : HasNonnegCoeffs (C t * a) := - nonnegCoeffs_C_mul ht ha + hasNonnegCoeffs_C_mul ht ha have hsum : HasNonnegCoeffs (C s * (X * a) + (C t * a + b)) := hsa.add (hta.add hb) grind diff --git a/RealRooted/MultiplierSequence/Infinite.lean b/RealRooted/MultiplierSequence/Infinite.lean index 7bfd75e71..05c2aadd4 100644 --- a/RealRooted/MultiplierSequence/Infinite.lean +++ b/RealRooted/MultiplierSequence/Infinite.lean @@ -240,11 +240,8 @@ theorem isMultiplierSequence_natCast : rw [isMultiplierSequence_iff_preserves] intro p hp rw [← eulerOperator_eq_diagonalOperator_natCast] - rcases eq_zero_or_splits_derivative (Or.inr hp) with hder | hder - · left - simp [hder] - · right - exact Polynomial.splits_X_mul.mpr hder + right + exact Polynomial.splits_X_mul.mpr hp.derivative /-- Every nonnegative integral shift `k + r` of the Euler diagonal is an infinite multiplier sequence. -/ diff --git a/RealRooted/MultiplierSequence/InvPochhammer.lean b/RealRooted/MultiplierSequence/InvPochhammer.lean index e7edb604f..33a539517 100644 --- a/RealRooted/MultiplierSequence/InvPochhammer.lean +++ b/RealRooted/MultiplierSequence/InvPochhammer.lean @@ -63,7 +63,7 @@ theorem isPFMultiplierSequence_inv_ascPochhammer {α : ℝ} (hα : 0 < α) : inv_mul_cancel₀ hpos.ne', C_1, one_mul] rw [heq] exact IsPFPolynomial.of_realRooted_nonneg - (nonnegCoeffs_C_mul (inv_pos.mpr hpos).le + (hasNonnegCoeffs_C_mul (inv_pos.mpr hpos).le (generalizedLaguerre_hasNonnegCoeffs n hα1)) ((generalizedLaguerre_splits n hα1).C_mul _) diff --git a/RealRooted/MultiplierSequence/PolyaSchur/LaguerrePolya/Derivative.lean b/RealRooted/MultiplierSequence/PolyaSchur/LaguerrePolya/Derivative.lean index 348befc6d..7887740b5 100644 --- a/RealRooted/MultiplierSequence/PolyaSchur/LaguerrePolya/Derivative.lean +++ b/RealRooted/MultiplierSequence/PolyaSchur/LaguerrePolya/Derivative.lean @@ -56,7 +56,7 @@ theorem IsLaguerrePolya.deriv {f : ℂ → ℂ} (hf : IsLaguerrePolya f) : IsLaguerrePolya (deriv f) := by rcases hf with ⟨p, hp, hptend⟩ refine ⟨fun n => (p n).derivative, fun n => - eq_zero_or_splits_derivative (hp n), ?_⟩ + Or.inr ((hp n).elim (fun h => h ▸ Splits.zero) id |>.derivative), ?_⟩ have hderiv := (tendstoLocallyUniformlyOn_univ.mpr hptend).deriv (Eventually.of_forall fun n => (Polynomial.differentiable ((p n).map Complex.ofRealHom)).differentiableOn) diff --git a/RealRooted/MultiplierSequence/PolyaSchur/Schur.lean b/RealRooted/MultiplierSequence/PolyaSchur/Schur.lean index e8683d4d4..f76e2c69a 100644 --- a/RealRooted/MultiplierSequence/PolyaSchur/Schur.lean +++ b/RealRooted/MultiplierSequence/PolyaSchur/Schur.lean @@ -29,7 +29,7 @@ coefficient is PF. -/ private theorem isPFPolynomial_of_splits_of_roots_nonpos {g : ℝ[X]} (hg : g.Splits) (hroots : ∀ r ∈ g.roots, r ≤ 0) (hlc : 0 ≤ g.leadingCoeff) : IsPFPolynomial g := by - rw [← C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hg)] + rw [← C_leadingCoeff_mul_prod_multiset_X_sub_C (Polynomial.splits_iff_card_roots.mp hg)] refine (IsPFPolynomial.of_C_nonneg hlc).mul ?_ generalize g.roots = t at hroots ⊢ induction t using Multiset.induction_on with diff --git a/RealRooted/MultiplierSequence/ProperPosition.lean b/RealRooted/MultiplierSequence/ProperPosition.lean index a553520ad..fc67aaafc 100644 --- a/RealRooted/MultiplierSequence/ProperPosition.lean +++ b/RealRooted/MultiplierSequence/ProperPosition.lean @@ -135,10 +135,10 @@ theorem IsFiniteMultiplierSequence.strictInterl_diagonalOperator · by_cases hd : f.natDegree = 0 · have hroots_f : (diagonalOperator gamma f).roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hTf_splits, hfd, hd] + rw [Polynomial.splits_iff_card_roots.mp hTf_splits, hfd, hd] have hroots_g : (diagonalOperator gamma g).roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hTg_splits, hgd, hsame, hd] + rw [Polynomial.splits_iff_card_roots.mp hTg_splits, hgd, hsame, hd] apply hreverse.of_reverse_of_roots_sum_le hdeg_out rw [hroots_f, hroots_g] · have hpos : 0 < f.natDegree := Nat.pos_of_ne_zero hd diff --git a/RealRooted/NarayanaTransformation/Basis.lean b/RealRooted/NarayanaTransformation/Basis.lean index b16c8320a..1cdddff66 100644 --- a/RealRooted/NarayanaTransformation/Basis.lean +++ b/RealRooted/NarayanaTransformation/Basis.lean @@ -104,10 +104,9 @@ private theorem touchardFactorStep_preservesPF {r : ℝ} (hr : 0 ≤ r) hasPosLeadingCoeff_add_of_natDegree_lt_left (by lia) hfirst_pos have hsum_deg : ((X + C r) * f + X * f.derivative).natDegree = f.natDegree + 1 := by - rw [natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff] + rw [Polynomial.natDegree_add_eq_left_of_natDegree_lt] · exact hfirst_deg · lia - · exact hfirst_pos have hstrictInterl : StrictInterl f ((X + C r) * f + X * f.derivative) := by apply strictInterl_of_interlaces_evalCoeff_nonpos hder hder_pos hsum_pos · rw [hsum_deg] @@ -340,7 +339,7 @@ theorem risingFactorialStep_pf_shiftStrictInterl hfμ.hasNonnegCoeffs hfμ.hasNonnegCoeffs have hXfμnn : HasNonnegCoeffs (X * fμ) := hfμ.X_mul.hasNonnegCoeffs have hrf_nn : HasNonnegCoeffs (C r * f) := - nonnegCoeffs_C_mul hr hf.hasNonnegCoeffs + hasNonnegCoeffs_C_mul hr hf.hasNonnegCoeffs have hf_g0 : Interl f (X * fμ + C r * f) := interl_add_right_of_common_left_of_nonneg hf_Xfμ.toInterl (Interl.C_mul_right_of_nonneg hf.interl_self hr) hXfμnn hrf_nn @@ -369,11 +368,9 @@ theorem risingFactorialStep_pf_shiftStrictInterl simp [add_comm] have hrfdeg : (C r * f).natDegree ≤ f.natDegree := Polynomial.natDegree_C_mul_le r f have hgdeg : (X * fμ + C r * f).natDegree = f.natDegree + 1 := by - rw [natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff] + rw [Polynomial.natDegree_add_eq_left_of_natDegree_lt] · exact hXfμdeg - · rw [hXfμdeg] - lia - · exact (hfμ.hasNonnegCoeffs.pos_leadingCoeff hfμrr.1).X_mul + · lia have hgpf : IsPFPolynomial (X * fμ + C r * f) := IsPFPolynomial.of_realRooted_nonneg (hXfμnn.add hrf_nn) hfg.2.1.2 exact ⟨hgpf, strictInterl_comp_X_add_C_of_two_interlacings hμ hfg hfμg (by lia)⟩ diff --git a/RealRooted/ObreschkoffContinuity.lean b/RealRooted/ObreschkoffContinuity.lean index f6f0b6401..14ccce667 100644 --- a/RealRooted/ObreschkoffContinuity.lean +++ b/RealRooted/ObreschkoffContinuity.lean @@ -160,9 +160,12 @@ theorem im_eq_zero_of_aeval_zero_of_monic_sameDegree obtain ⟨w, hw_root, hw_dist⟩ := exists_complex_aroot_near_right_family (hfg := hfg) (hz := hz) hf_monic hg_monic hdeg hμ hcoeff_bound - have hw_im_zero : w.im = 0 := - RealRooted.im_eq_zero_of_mem_aroots_of_isRealRooted - (hfg.isRealRooted_add_right hμ).1 (hfg.isRealRooted_add_right hμ).2 hw_root + have hsum_rr := hfg.isRealRooted_add_right hμ + have hw_isRoot : ((f + C μ * g).map (algebraMap ℝ ℂ)).IsRoot w := by + simp_all + have hw_im_zero : w.im = 0 := by + rcases hsum_rr.2.mem_range_of_isRoot hsum_rr.1 hw_isRoot with ⟨r, rfl⟩ + simp have hbound_eq : ((f.natDegree + 1) * ε) ^ ((f.natDegree : ℝ)⁻¹) * R = δ / 2 := by have hmul : diff --git a/RealRooted/ObreschkoffConverse/Converse.lean b/RealRooted/ObreschkoffConverse/Converse.lean index 17cc8eb66..7666b497c 100644 --- a/RealRooted/ObreschkoffConverse/Converse.lean +++ b/RealRooted/ObreschkoffConverse/Converse.lean @@ -41,7 +41,7 @@ private theorem isRealRooted_of_consecutive_signs_of_natDegree_eq_of_outer_root (F := F) hrs_sorted (by grind) have hrs_len : rs.length = f.natDegree := by rw [show rs = f.roots.sort (· ≤ ·) by lia, Multiset.length_sort, - card_roots_of_splits hf_splits] + Polynomial.splits_iff_card_roots.mp hf_splits] have hrs_ne : rs ≠ [] := by grind have hus_sub : (↑us : Multiset ℝ) ≤ F.roots := by rw [Multiset.le_iff_subset (Multiset.coe_nodup.mpr (hus_pw.imp ne_of_lt))] @@ -50,7 +50,7 @@ private theorem isRealRooted_of_consecutive_signs_of_natDegree_eq_of_outer_root have hus_len_deg : us.length = F.natDegree - 1 := by lia have hsplits {ws : List ℝ} (hsub : (↑ws : Multiset ℝ) ≤ F.roots) (hlen : ws.length = F.natDegree) : F.Splits := by - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr exact le_antisymm (card_roots' F) (by simpa [hlen] using Multiset.card_le_card hsub) rcases houter with ⟨uL, huL_root, huL_lt⟩ | ⟨uR, huR_root, huR_lt⟩ @@ -129,7 +129,8 @@ theorem ObreschkoffConverseInternal.isRealRooted_of_interlaces_eval_mul_neg_same have hF_lc_neg : F.leadingCoeff < 0 := lt_of_le_of_ne (not_lt.mp hF_pos) hF_lc_ne have hrs_len : rs.length = f.natDegree := by - rw [show rs = f.roots.sort (· ≤ ·) by lia, Multiset.length_sort, card_roots_of_splits hf.2] + rw [show rs = f.roots.sort (· ≤ ·) by lia, Multiset.length_sort, + Polynomial.splits_iff_card_roots.mp hf.2] have hrs_ne : rs ≠ [] := by intro h rw [h] at hrs_len diff --git a/RealRooted/ObreschkoffConverse/DegreeGap.lean b/RealRooted/ObreschkoffConverse/DegreeGap.lean index c80d8093c..fad09294c 100644 --- a/RealRooted/ObreschkoffConverse/DegreeGap.lean +++ b/RealRooted/ObreschkoffConverse/DegreeGap.lean @@ -44,7 +44,7 @@ lemma exists_root_ge_of_derivative_root obtain ⟨hp_rr, hp'_rr, _, rs, ss, hrs_sorted, hss_sorted, hrs_eq, hss_eq, hint⟩ := derivative_interlaces_of_natDegree_ne_zero hp_splits (by lia) have hrs_len : rs.length = p.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hp_rr.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hp_rr.2] have hrs_ne : rs ≠ [] := by grind have hc_mem : c ∈ ss := by apply Multiset.mem_coe.mp diff --git a/RealRooted/ObreschkoffConverse/Derivative.lean b/RealRooted/ObreschkoffConverse/Derivative.lean index 9570a0d0b..289e8ee19 100644 --- a/RealRooted/ObreschkoffConverse/Derivative.lean +++ b/RealRooted/ObreschkoffConverse/Derivative.lean @@ -123,10 +123,10 @@ lemma StrictInterl.of_degree_zero_degree_zero StrictInterl f g := by have hroots_f : f.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hf_splits, hf_deg0] + rw [Polynomial.splits_iff_card_roots.mp hf_splits, hf_deg0] have hroots_g : g.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hg_splits, hg_deg0] + rw [Polynomial.splits_iff_card_roots.mp hg_splits, hg_deg0] refine ⟨⟨hf_ne, hf_splits⟩, ⟨hg_ne, hg_splits⟩, [], [], by simp, by simp, ?_, ?_, ?_⟩ · simp [hroots_f] · simp [hroots_g] diff --git a/RealRooted/ObreschkoffConverse/Forward.lean b/RealRooted/ObreschkoffConverse/Forward.lean index 2fbb985db..a8099f5ba 100644 --- a/RealRooted/ObreschkoffConverse/Forward.lean +++ b/RealRooted/ObreschkoffConverse/Forward.lean @@ -51,8 +51,7 @@ private theorem allComboRealRooted_of_strictInterl_succDegree_pos (C (-β) * g + C (-α) * f).natDegree = g.natDegree := by calc (C (-β) * g + C (-α) * f).natDegree = (C (-β) * g).natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg_scaled - (hasPosLeadingCoeff_C_mul (by simp_all) hg_pos) + Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg_scaled _ = g.natDegree := by rw [natDegree_C_mul (by simp_all : (-β) ≠ 0)] have hrr_neg : ((C (-β) * g + C (-α) * f) ≠ 0 ∧ (C (-β) * g + C (-α) * f).Splits) := by @@ -89,8 +88,7 @@ private theorem allComboRealRooted_of_strictInterl_succDegree_pos (C β * g + C α * f).natDegree = g.natDegree := by calc (C β * g + C α * f).natDegree = (C β * g).natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg_scaled - (hasPosLeadingCoeff_C_mul hβpos hg_pos) + Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg_scaled _ = g.natDegree := by rw [natDegree_C_mul hβ0] have hstrictInterl_mix : StrictInterl g (C β * g + C α * f) := diff --git a/RealRooted/ObreschkoffConverse/Regularization.lean b/RealRooted/ObreschkoffConverse/Regularization.lean index 9d99ba010..ec5992694 100644 --- a/RealRooted/ObreschkoffConverse/Regularization.lean +++ b/RealRooted/ObreschkoffConverse/Regularization.lean @@ -110,9 +110,10 @@ private lemma wronskian_eval_ne_zero_of_eq_zero_or_simple_combo have hscale_ne : f.eval x / g.eval x ≠ 0 := div_ne_zero hfx0 hgx0 have hdeg_eq : f.natDegree = g.natDegree := by rw [hscalar, natDegree_C_mul hscale_ne] have hg_deg_pos : 0 < g.natDegree := by grind - obtain ⟨r, hr⟩ := - exists_isRoot_of_isRealRooted_of_not_isUnit hg_ne hg_splits - (not_isUnit_of_natDegree_pos g hg_deg_pos) + obtain ⟨r, hr⟩ : ∃ r : ℝ, g.IsRoot r := by + simpa [Polynomial.IsRoot.def] using hg_splits.exists_eval_eq_zero + (degree_pos_of_ne_zero_of_nonunit hg_ne + (not_isUnit_of_natDegree_pos g hg_deg_pos)).ne' have hfr : f.IsRoot r := by have hgr_eval : g.eval r = 0 := by simpa [Polynomial.IsRoot.def] using hr have hfr_eval : f.eval r = 0 := by @@ -360,9 +361,10 @@ lemma ObreschkoffConverseInternal.no_nontrivial_linear_relation_of_no_common_roo have hcoeff := congrArg (fun q : ℝ[X] => q.coeff n) hEq grind have hscale_ne : (-β) / α ≠ 0 := div_ne_zero (neg_ne_zero.mpr hβ) hα - obtain ⟨r, hr⟩ := - exists_isRoot_of_isRealRooted_of_not_isUnit hf_ne hf_splits - (not_isUnit_of_natDegree_pos f hf_deg_pos) + obtain ⟨r, hr⟩ : ∃ r : ℝ, f.IsRoot r := by + simpa [Polynomial.IsRoot.def] using hf_splits.exists_eval_eq_zero + (degree_pos_of_ne_zero_of_nonunit hf_ne + (not_isUnit_of_natDegree_pos f hf_deg_pos)).ne' simp_all private lemma no_common_root_iterateTDeriv_of_allComboRealRooted @@ -412,7 +414,7 @@ private lemma no_common_root_iterateTDeriv_of_allComboRealRooted have hcard : 0 < (iterateTDeriv eps (max f.natDegree g.natDegree) f).roots.card := Multiset.card_pos_iff_exists_mem.mpr ⟨r, hr_mem⟩ - rw [card_roots_of_splits hf'.2] at hcard + rw [Polynomial.splits_iff_card_roots.mp hf'.2] at hcard lia have hf_deg_pos : 0 < f.natDegree := by simp_all exact ObreschkoffConverseInternal.no_nontrivial_linear_relation_of_no_common_root @@ -489,10 +491,10 @@ private theorem strictInterl_or_reverse_of_eq_zero_or_simple_combo_sameDegree · have hgdeg0 : g.natDegree = 0 := by lia have hroots_f : f.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hf_splits, hdeg0] + rw [Polynomial.splits_iff_card_roots.mp hf_splits, hdeg0] have hroots_g : g.roots = 0 := by apply Multiset.card_eq_zero.mp - rw [card_roots_of_splits hg_splits, hgdeg0] + rw [Polynomial.splits_iff_card_roots.mp hg_splits, hgdeg0] left refine ⟨⟨hf_ne, hf_splits⟩, ⟨hg_ne, hg_splits⟩, [], [], by simp, by simp, diff --git a/RealRooted/OperatorInterlacingUpgrade.lean b/RealRooted/OperatorInterlacingUpgrade.lean index b8904d2cc..bc81607a1 100644 --- a/RealRooted/OperatorInterlacingUpgrade.lean +++ b/RealRooted/OperatorInterlacingUpgrade.lean @@ -224,18 +224,18 @@ theorem preservesPFShiftInterlacingOnDegree_of_monomials hFnn hGnn hHnn hFG' hGH' hfamily ha have hAnn : HasNonnegCoeffs (quadraticInterlacingTangent F G (-u)) := - hGnn.add (nonnegCoeffs_C_mul ha hFnn) + hGnn.add (hasNonnegCoeffs_C_mul ha hFnn) have hBnn : HasNonnegCoeffs (quadraticInterlacingRight G H (-u)) := - hHnn.add (nonnegCoeffs_C_mul ha hGnn) + hHnn.add (hasNonnegCoeffs_C_mul ha hGnn) have hQnn : HasNonnegCoeffs (quadraticInterlacingPencil F G H (-u)) := by - exact (hHnn.add (nonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha) hGnn)).add - (nonnegCoeffs_C_mul (sq_nonneg (-u)) hFnn) + exact (hHnn.add (hasNonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha) hGnn)).add + (hasNonnegCoeffs_C_mul (sq_nonneg (-u)) hFnn) have hB0 : quadraticInterlacingRight G H (-u) ≠ 0 := by have hsum : C (-u) * G + H ≠ 0 := add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - (nonnegCoeffs_C_mul ha hGnn) hHnn hGH'.2.1.1 + (hasNonnegCoeffs_C_mul ha hGnn) hHnn hGH'.2.1.1 simpa [quadraticInterlacingRight, add_comm] using hsum have hstep : StrictInterl (quadraticInterlacingTangent F G (-u)) diff --git a/RealRooted/OperatorInterlacingUpgrade/RootOrder.lean b/RealRooted/OperatorInterlacingUpgrade/RootOrder.lean index 8df861f57..dd94f8291 100644 --- a/RealRooted/OperatorInterlacingUpgrade/RootOrder.lean +++ b/RealRooted/OperatorInterlacingUpgrade/RootOrder.lean @@ -310,7 +310,7 @@ theorem PreservesFullDegreeRootMoves.rootwiseLE_bounds RootwiseLE (T p) (T ((X + C a) ^ D)) := by let ps := p.roots.sort (· ≤ ·) have hps_len : ps.length = D := by - simp [ps, card_roots_of_splits hsplits, hdeg] + simp [ps, Polynomial.splits_iff_card_roots.mp hsplits, hdeg] have hps_sort : (↑ps : Multiset ℝ) = p.roots := Multiset.sort_eq p.roots (· ≤ ·) have hlo_list : List.Forall₂ (· ≤ ·) (List.replicate D (-b)) ps := by @@ -360,7 +360,7 @@ theorem rootwiseLE_monomialChain_component_bounds RootwiseLE (T p) (T ((X + C a) ^ D)) := by let ps := p.roots.sort (· ≤ ·) have hps_len : ps.length = D := by - simp [ps, card_roots_of_splits hsplits, hdeg] + simp [ps, Polynomial.splits_iff_card_roots.mp hsplits, hdeg] have hps_sort : (↑ps : Multiset ℝ) = p.roots := Multiset.sort_eq p.roots (· ≤ ·) have hlo_list : List.Forall₂ (· ≤ ·) (List.replicate D (-b)) ps := by diff --git a/RealRooted/OperatorMatrix/Directed.lean b/RealRooted/OperatorMatrix/Directed.lean index 0df42052e..b1c790e82 100644 --- a/RealRooted/OperatorMatrix/Directed.lean +++ b/RealRooted/OperatorMatrix/Directed.lean @@ -291,8 +291,7 @@ theorem interl_derivative_add_derivative_add_X_mul_derivative_of_isCoprime rcases hpq.natDegree_eq_or_eq_succ with hsame | hsucc · exact (natDegree_add_eq_of_same_natDegree_of_posLeadingCoeff hsame.symm hp_pos hq_pos).trans hsame.symm - · exact natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - (by lia) hq_pos + · exact Polynomial.natDegree_add_eq_right_of_natDegree_lt (by lia) have hF_pf : IsPFPolynomial F := by simpa [F] using isPFPolynomial_add_X_mul_derivative_of_interl hp hq hpq.toInterl diff --git a/RealRooted/OperatorMatrix/MixedLemma.lean b/RealRooted/OperatorMatrix/MixedLemma.lean index 1ce8bef3b..3e42e812d 100644 --- a/RealRooted/OperatorMatrix/MixedLemma.lean +++ b/RealRooted/OperatorMatrix/MixedLemma.lean @@ -451,7 +451,7 @@ theorem interl_derivative_add_derivative_add_X_mul_derivative {p q : ℝ[X]} change (rootApproxEven p.leadingCoeff ss (delta M)).natDegree = p.natDegree rw [rootApproxEven, natDegree_C_mul_rootPolynomial hpLeading.ne'] change (separateEven (delta M) ss).length = p.natDegree - have hcard := card_roots_of_splits hpReal.2 + have hcard := Polynomial.splits_iff_card_roots.mp hpReal.2 rw [← hssRoots] at hcard change ss.length = p.natDegree at hcard exact (length_separateEven (delta M) ss).trans hcard @@ -459,7 +459,7 @@ theorem interl_derivative_add_derivative_add_X_mul_derivative {p q : ℝ[X]} change (rootApproxOdd q.leadingCoeff rs (delta M)).natDegree = q.natDegree rw [rootApproxOdd, natDegree_C_mul_rootPolynomial hqLeading.ne'] change (separateOdd (delta M) rs).length = q.natDegree - have hcard := card_roots_of_splits hqReal.2 + have hcard := Polynomial.splits_iff_card_roots.mp hqReal.2 rw [← hrsRoots] at hcard change rs.length = q.natDegree at hcard exact (length_separateOdd (delta M) rs).trans hcard @@ -467,12 +467,12 @@ theorem interl_derivative_add_derivative_add_X_mul_derivative {p q : ℝ[X]} simp only [rootApproxEven, separateEven_zero] rw [hssRoots] exact C_leadingCoeff_mul_prod_multiset_X_sub_C - (card_roots_of_splits hpReal.2) + (Polynomial.splits_iff_card_roots.mp hpReal.2) have hqAtZero : rootApproxOdd q.leadingCoeff rs 0 = q := by simp only [rootApproxOdd, separateOdd_zero] rw [hrsRoots] exact C_leadingCoeff_mul_prod_multiset_X_sub_C - (card_roots_of_splits hqReal.2) + (Polynomial.splits_iff_card_roots.mp hqReal.2) have hpCoeff (i : ℕ) : Tendsto (fun M => (pM M).coeff i) atTop (nhds (p.coeff i)) := by simpa only [pM, hpAtZero, Function.comp_def] using diff --git a/RealRooted/OrderedRoots.lean b/RealRooted/OrderedRoots.lean index 088cda3a2..8fdc20070 100644 --- a/RealRooted/OrderedRoots.lean +++ b/RealRooted/OrderedRoots.lean @@ -32,7 +32,7 @@ theorem orderedRoot_isRoot_of_splits (hdeg : p.natDegree = n) (i : Fin n) : p.IsRoot (orderedRoot p n i) := Polynomial.isRoot_of_mem_roots <| - orderedRoot_mem_roots (by rw [card_roots_of_splits hp, hdeg]) i + orderedRoot_mem_roots (by rw [Polynomial.splits_iff_card_roots.mp hp, hdeg]) i /-- For two nonzero, split polynomials of degree `n`, interlacing is equivalent to the coordinate bounds on their canonically ordered roots. -/ @@ -49,9 +49,9 @@ theorem strictInterl_iff_orderedRoot_bounds · intro h obtain ⟨_, _, ss, rs, hss, hrs, hss_eq, hrs_eq, hshape⟩ := h have hssLength : ss.length = n := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hpSplits, hpDegree] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hpSplits, hpDegree] have hrsLength : rs.length = n := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hqSplits, hqDegree] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hqSplits, hqDegree] obtain ⟨_, halt⟩ := hshape.resolve_left (by intro hbad; lia) have hssCanonical : p.roots.sort (· ≤ ·) = ss := by rw [← hss_eq, Multiset.coe_sort] @@ -77,10 +77,10 @@ theorem strictInterl_iff_orderedRoot_bounds let rs := q.roots.sort (· ≤ ·) have hssLength : ss.length = n := by rw [show ss = p.roots.sort (· ≤ ·) by rfl, Multiset.length_sort, - card_roots_of_splits hpSplits, hpDegree] + Polynomial.splits_iff_card_roots.mp hpSplits, hpDegree] have hrsLength : rs.length = n := by rw [show rs = q.roots.sort (· ≤ ·) by rfl, Multiset.length_sort, - card_roots_of_splits hqSplits, hqDegree] + Polynomial.splits_iff_card_roots.mp hqSplits, hqDegree] refine ⟨⟨hpNe, hpSplits⟩, ⟨hqNe, hqSplits⟩, ss, rs, Multiset.pairwise_sort .., Multiset.pairwise_sort .., ?_, ?_, Or.inr ⟨by lia, ?_⟩⟩ diff --git a/RealRooted/PFPolynomial.lean b/RealRooted/PFPolynomial.lean index 471cc9bf4..54df4318b 100644 --- a/RealRooted/PFPolynomial.lean +++ b/RealRooted/PFPolynomial.lean @@ -69,25 +69,27 @@ theorem of_nonnegCoeffs_eq_zero_or_splits {p : ℝ[X]} theorem const_mul {a : ℝ} (ha : 0 < a) {p : ℝ[X]} (hp : IsPFPolynomial p) : IsPFPolynomial (C a * p) := - IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits - (nonnegCoeffs_C_mul ha.le hp.hasNonnegCoeffs) - (mul_eq_zero_or_splits (Or.inr (by simp)) hp.eq_zero_or_splits) + IsPFPolynomial.of_realRooted_nonneg + (hasNonnegCoeffs_C_mul ha.le hp.hasNonnegCoeffs) + ((hp.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id).C_mul a) theorem of_C_nonneg {a : ℝ} (ha : 0 ≤ a) : IsPFPolynomial (Polynomial.C a) := IsPFPolynomial.of_realRooted_nonneg (hasNonnegCoeffs_C ha) (by simp) theorem X_mul {p : ℝ[X]} (hp : IsPFPolynomial p) : IsPFPolynomial (X * p) := - IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits + IsPFPolynomial.of_realRooted_nonneg (hasNonnegCoeffs_X.mul hp.hasNonnegCoeffs) - (mul_eq_zero_or_splits (Or.inr (by simp)) hp.eq_zero_or_splits) + ((by simp : (X : ℝ[X]).Splits).mul + (hp.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id)) theorem mul {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) : IsPFPolynomial (p * q) := - IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits + IsPFPolynomial.of_realRooted_nonneg (hp.hasNonnegCoeffs.mul hq.hasNonnegCoeffs) - (mul_eq_zero_or_splits hp.eq_zero_or_splits hq.eq_zero_or_splits) + ((hp.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id).mul + (hq.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id)) /-- If a PF polynomial is factored by a real linear factor, then the quotient is again PF. -/ @@ -122,7 +124,7 @@ theorem exists_X_sub_C_factor_of_pos_natDegree {p : ℝ[X]} have hp0 : p ≠ 0 := by grind have hpsplits : p.Splits := hp.ne_zero_and_splits hp0 |>.2 have hroots_pos : 0 < p.roots.card := by - rw [card_roots_of_splits hpsplits] + rw [Polynomial.splits_iff_card_roots.mp hpsplits] exact hdeg rcases Multiset.card_pos_iff_exists_mem.mp hroots_pos with ⟨u, hu_mem⟩ have hu_root : p.IsRoot u := (mem_roots hp0).mp hu_mem @@ -207,14 +209,14 @@ theorem exists_pos_multiset_prod_one_add_C_mul_X {p : ℝ[X]} theorem pow {p : ℝ[X]} (hp : IsPFPolynomial p) (n : ℕ) : IsPFPolynomial (p ^ n) := - IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits - (hp.hasNonnegCoeffs.pow n) (pow_eq_zero_or_splits hp.eq_zero_or_splits n) + IsPFPolynomial.of_realRooted_nonneg (hp.hasNonnegCoeffs.pow n) + ((hp.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id).pow n) theorem derivative {p : ℝ[X]} (hp : IsPFPolynomial p) : IsPFPolynomial p.derivative := - IsPFPolynomial.of_nonnegCoeffs_eq_zero_or_splits hp.hasNonnegCoeffs.derivative - (eq_zero_or_splits_derivative hp.eq_zero_or_splits) + IsPFPolynomial.of_realRooted_nonneg hp.hasNonnegCoeffs.derivative + (hp.eq_zero_or_splits.elim (fun h => h ▸ Splits.zero) id).derivative /-- Construct a PF polynomial directly from its Pólya-frequency coefficient sequence using the proved forward ASW theorem. -/ @@ -338,7 +340,7 @@ theorem IsPFPolynomial.reverse {p : ℝ[X]} (hp : IsPFPolynomial p) : (by rcases hp.eq_zero_or_splits with rfl | hsplits · exact Or.inl (by simp) - · exact Or.inr (DegreeDropReversal.splits_reverse hsplits)) + · exact Or.inr (Polynomial.Splits.reverse hsplits)) theorem reverse_X_sub_C_isPF {r : ℝ} (hr : r ≤ 0) : IsPFPolynomial ((X - C r : ℝ[X]).reverse) := by @@ -360,13 +362,13 @@ theorem isPFPolynomial_reverse_prod_X_sub_C exact hr.mul (ih fun x hx => hs x (by simp [hx])) theorem interl_X_mul_both_of_pf {p q : ℝ[X]} - (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) + (_hp : IsPFPolynomial p) (_hq : IsPFPolynomial q) (hpq : Interl p q) : Interl (X * p) (X * q) := by rcases hpq with hp0 | hq0 | hpq' · simpa [hp0] using interl_zero_left (X * q) · simpa [hq0] using interl_zero_right (X * p) - · exact (hpq'.mul_X_both_of_roots_nonpos hp.roots_nonpos hq.roots_nonpos).toInterl + · exact (by simpa using hpq'.mul_X_sub_C_both 0 : StrictInterl (X * p) (X * q)).toInterl /-- Fixed-left cone closure in the two-summand form used downstream: if a polynomial is a common left interleaver for two nonnegative-coefficient @@ -408,7 +410,7 @@ theorem interl_nonneg_combo_right_of_common_left_of_nonneg {p q r : ℝ[X]} interl_add_right_of_common_left_of_nonneg (Interl.C_mul_right_of_nonneg hpq ha) (Interl.C_mul_right_of_nonneg hpr hb) - (nonnegCoeffs_C_mul ha hq) (nonnegCoeffs_C_mul hb hr) + (hasNonnegCoeffs_C_mul ha hq) (hasNonnegCoeffs_C_mul hb hr) /-- Fixed-left cone closure in the polynomial PF notation. -/ theorem interl_nonneg_combo_right_of_common_left_of_pf {p q r : ℝ[X]} diff --git a/RealRooted/ParkingFunctions/Descents/WeakLeftPeakOrderedCut.lean b/RealRooted/ParkingFunctions/Descents/WeakLeftPeakOrderedCut.lean index b6ac063a0..341eccca6 100644 --- a/RealRooted/ParkingFunctions/Descents/WeakLeftPeakOrderedCut.lean +++ b/RealRooted/ParkingFunctions/Descents/WeakLeftPeakOrderedCut.lean @@ -134,7 +134,7 @@ theorem terminalPairMixReal_orderedCutCompatible_zero (m : ℕ) : HasNonnegCoeffs (terminalXPairMixReal m 0 i) := by rw [terminalXPairMixReal_zero_closed] exact - (nonnegCoeffs_C_mul (by positivity) hasNonnegCoeffs_X).add + (hasNonnegCoeffs_C_mul (by positivity) hasNonnegCoeffs_X).add (hasNonnegCoeffs_C (by positivity)) have hQ_pos (i : Fin m) : HasPosLeadingCoeff (terminalXPairMixReal m 0 i) := by diff --git a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/NodeInterlacing.lean b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/NodeInterlacing.lean index e7e33748d..fcc8372a0 100644 --- a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/NodeInterlacing.lean +++ b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/NodeInterlacing.lean @@ -95,9 +95,9 @@ private theorem Interlaces.orderedRoot_bounds {g f : ℝ[X]} {n : ℕ} orderedRoot g n i ≤ orderedRoot f (n + 1) i.succ := by obtain ⟨hf, hg, _, rs, ss, hrs, hss, hrs_eq, hss_eq, hint⟩ := h have hrs_len : rs.length = n + 1 := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf.2, hfdeg] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf.2, hfdeg] have hss_len : ss.length = n := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hg.2, hgdeg] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hg.2, hgdeg] have hrs_canonical : f.roots.sort (· ≤ ·) = rs := by rw [← hrs_eq, Multiset.coe_sort] exact List.mergeSort_eq_self (· ≤ ·) hrs @@ -292,7 +292,8 @@ private theorem exceptionalBasePolynomial_strictInterl_exceptionalEulerInverse simpa only [mul_comm] using hFlead have hUne : U ≠ 0 := fun hzero => by rw [hzero] at hUdegree; simp_all have huSplits : u.Splits := - (isRealRooted_comp_one_sub_X hUne hUsplits).2 + hUsplits.comp_of_natDegree_le_one + ((natDegree_sub_le (1 : ℝ[X]) X).trans (by simp)) have hrec : C γ * f = C γ * u + -(1 - X) * u.derivative := by have heuler := eulerShiftOperator_exceptionalEulerInverse m ε hγ have hcomp := congrArg (fun p : ℝ[X] => p.comp (1 - X)) heuler @@ -745,10 +746,10 @@ private theorem interlaces_of_intervalRootData_orderedRoot_bounds have hgNe : g ≠ 0 := hg.ne_zero have hrsLength : rs.length = n + 1 := by rw [show rs = f.roots.sort (· ≤ ·) by rfl, Multiset.length_sort, - card_roots_of_splits hfSplits, hfDegree] + Polynomial.splits_iff_card_roots.mp hfSplits, hfDegree] have hssLength : ss.length = n := by rw [show ss = g.roots.sort (· ≤ ·) by rfl, Multiset.length_sort, - card_roots_of_splits hg.splits, hg.natDegree_eq] + Polynomial.splits_iff_card_roots.mp hg.splits, hg.natDegree_eq] refine ⟨⟨hfNe, hfSplits⟩, ⟨hgNe, hg.splits⟩, ?_, rs, ss, by simp [rs], by simp [ss], by simp [rs], by simp [ss], ?_⟩ · rw [hg.natDegree_eq, hfDegree] diff --git a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/PencilSplitting.lean b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/PencilSplitting.lean index 5d50c39f4..f225e7a9f 100644 --- a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/PencilSplitting.lean +++ b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/PencilSplitting.lean @@ -722,7 +722,7 @@ theorem exceptionalEulerInverse_pencil_splits_of_eval_one_ne_zero rw [hfactor] exact hQ have hPsplit : P.Splits := by - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr rw [show P = interiorRootProduct Q by rfl, interiorRootProduct, Polynomial.roots_multiset_prod_X_sub_C, Polynomial.natDegree_multiset_prod_X_sub_C_eq_card] diff --git a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/ProperPositionAndParameters.lean b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/ProperPositionAndParameters.lean index 1b077f6fe..ed068d13d 100644 --- a/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/ProperPositionAndParameters.lean +++ b/RealRooted/ParkingFunctions/ToricContribution/ExceptionalOffset/ProperPositionAndParameters.lean @@ -80,7 +80,7 @@ theorem exceptionalEulerInverse_roots_pos dsimp only [R] exact natDegree_exceptionalEulerInverse m ε hγpos have hcardRoots : R.roots.card = m := by - rw [card_roots_of_splits hsplit, hdegree] + rw [Polynomial.splits_iff_card_roots.mp hsplit, hdegree] have hOne : R.eval 1 ≠ 0 := by have hsign := negOnePow_mul_exceptionalEulerInverse_eval_one_pos @@ -177,7 +177,7 @@ private theorem neg_coeff_one_eq_sum_roots_inv Polynomial.roots_reverse_eq_map_inv hp hzeroNe have hnext := - (DegreeDropReversal.splits_reverse hp).nextCoeff_eq_neg_sum_roots_mul_leadingCoeff + (Polynomial.Splits.reverse hp).nextCoeff_eq_neg_sum_roots_mul_leadingCoeff rw [hrevNext, hrevLead, hroots] at hnext simp only [neg_mul, one_mul] at hnext linarith @@ -192,9 +192,9 @@ private theorem neg_coeff_one_le_of_strictInterl_sameDegree_of_roots_pos rcases hstrictInterl with ⟨hf, hg, ss, rs, hssSorted, hrsSorted, hssRoots, hrsRoots, hshape⟩ have hssLength : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hssRoots, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hssRoots, Polynomial.splits_iff_card_roots.mp hf.2] have hrsLength : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrsRoots, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrsRoots, Polynomial.splits_iff_card_roots.mp hg.2] have halt : ListAlternates ss rs := by rcases hshape with hinter | halt · exfalso diff --git a/RealRooted/ParkingFunctions/ToricContribution/FiniteOffsets.lean b/RealRooted/ParkingFunctions/ToricContribution/FiniteOffsets.lean index 106377d33..62e939677 100644 --- a/RealRooted/ParkingFunctions/ToricContribution/FiniteOffsets.lean +++ b/RealRooted/ParkingFunctions/ToricContribution/FiniteOffsets.lean @@ -55,7 +55,7 @@ private theorem diagonalEigenvalue_pos theorem IntervalRootData.roots_sort_length {p : ℝ[X]} {n : ℕ} (hp : IntervalRootData p n) : (p.roots.sort (· ≤ ·)).length = n := by - rw [Multiset.length_sort, card_roots_of_splits hp.splits, + rw [Multiset.length_sort, Polynomial.splits_iff_card_roots.mp hp.splits, hp.natDegree_eq] theorem IntervalRootData.orderedRoot_isRoot diff --git a/RealRooted/ParkingFunctions/ToricContribution/IntervalInsertion.lean b/RealRooted/ParkingFunctions/ToricContribution/IntervalInsertion.lean index fe7ac958f..329bfd663 100644 --- a/RealRooted/ParkingFunctions/ToricContribution/IntervalInsertion.lean +++ b/RealRooted/ParkingFunctions/ToricContribution/IntervalInsertion.lean @@ -162,9 +162,9 @@ theorem roots_neg_insertionOperator_mem_Ioo rcases hstrictInterl with ⟨hfrr, hFrr, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, hshape⟩ have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hfrr.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hfrr.2] have hrs_len : rs.length = F.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hFrr.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hFrr.2] have hint : ListInterlaces ss rs := by rcases hshape with ⟨_, hint⟩ | ⟨hlen, _⟩ · exact hint @@ -522,7 +522,7 @@ theorem insertionOperator_X_sub_C_data · simpa [hFdeg] using card_roots' F · simpa using Multiset.card_le_card hsub have hF_splits : F.Splits := by - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr simpa [hFdeg] using hcard have heq : (↑[sL, sR] : Multiset ℝ) = F.roots := Multiset.eq_of_le_of_card_le hsub (by simp [hcard]) @@ -590,14 +590,14 @@ theorem insertionOperator_natDegree_one_data (∀ r, (insertionOperator a b f).IsRoot r → (insertionOperator a b f).derivative.eval r ≠ 0) := by have hf_ne : f ≠ 0 := by rintro rfl; simp at hdeg - have hcard : f.roots.card = 1 := by rw [card_roots_of_splits hf, hdeg] + have hcard : f.roots.card = 1 := by rw [Polynomial.splits_iff_card_roots.mp hf, hdeg] obtain ⟨u, hu_roots⟩ := Multiset.card_eq_one.mp hcard have hu_root : f.IsRoot u := by exact (mem_roots hf_ne).mp (by simp [hu_roots]) have hu := hroots u hu_root have hfactor : f = C f.leadingCoeff * (X - C u) := by have hprod := - (C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hf)).symm + (C_leadingCoeff_mul_prod_multiset_X_sub_C (Polynomial.splits_iff_card_roots.mp hf)).symm rw [hu_roots] at hprod simpa using hprod rw [hfactor] diff --git a/RealRooted/PolarDerivative.lean b/RealRooted/PolarDerivative.lean index f63b56bca..4ba5f3c2e 100644 --- a/RealRooted/PolarDerivative.lean +++ b/RealRooted/PolarDerivative.lean @@ -15,7 +15,7 @@ Translate `a` to `0`: with `g = f.comp (X + C a)` we get `(D_a f).comp (X + C a) = n • g - X * g'`. On coefficients `n • g - X * g'` multiplies the coefficient of `X ^ i` by `n - i`, so it equals `reflect (n - 1) (derivative (reflect n g))`. Reversal preserves splitting over a field, and over `ℝ` the derivative of a split polynomial -splits by Rolle's theorem (`eq_zero_or_splits_derivative`). +splits by Rolle's theorem (`Polynomial.Splits.derivative`). ## Main results @@ -75,10 +75,8 @@ theorem splits_polarDerivative_of_splits {f : ℝ[X]} (hf : f.Splits) (a : ℝ) simp [g, natDegree_comp] have hs : ((polarDerivative a f).comp (X + C a)).Splits := by rw [polarDerivative_comp_X_add_C, C_mul_sub_X_mul_derivative_eq_reflect hdeg.le, ← hdeg] - refine DegreeDropReversal.splits_reflect_of_splits ?_ ?_ - · exact ((eq_zero_or_splits_derivative - (Or.inr (DegreeDropReversal.splits_reverse (hf.comp_X_add_C a)))).elim - (fun h => h ▸ Splits.zero) id) + refine Polynomial.Splits.reflect ?_ ?_ + · exact (Polynomial.Splits.reverse (hf.comp_X_add_C a)).derivative · exact (natDegree_derivative_le _).trans (Nat.sub_le_sub_right (reverse_natDegree_le g) 1) have h := hs.comp_X_sub_C a rwa [comp_assoc, add_comp, X_comp, C_comp, sub_add_cancel, comp_X] at h diff --git a/RealRooted/PosCombo.lean b/RealRooted/PosCombo.lean index 62044e901..7560789a4 100644 --- a/RealRooted/PosCombo.lean +++ b/RealRooted/PosCombo.lean @@ -308,7 +308,7 @@ lemma reflect_of_natDegree_le {f g : ℝ[X]} (hfg : PosComboRealRooted f g) {N : max_le ((Polynomial.natDegree_C_mul_le lam f).trans hfN) ((Polynomial.natDegree_C_mul_le μ g).trans hgN) - have hsplit_ref := DegreeDropReversal.splits_reflect_of_splits hsplits hdeg_combo + have hsplit_ref := Polynomial.Splits.reflect hsplits hdeg_combo have hne_ref : reflect N (C lam * f + C μ * g) ≠ 0 := fun hzero => hne (Polynomial.reflect_eq_zero_iff.mp hzero) simp_all @@ -739,7 +739,7 @@ theorem strictInterl_same_of_root_sign_data have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hlen : rs.length = f.natDegree := by rw [show rs = f.roots.sort (· ≤ ·) by lia, Multiset.length_sort, - card_roots_of_splits hf_splits] + Polynomial.splits_iff_card_roots.mp hf_splits] have hn : 1 ≤ rs.length := by lia have hg_ne : g ≠ 0 := hg_pos.ne_zero exact @@ -785,10 +785,10 @@ theorem strictInterl_or_reverse_of_same_degree_one have hf_rr : (f ≠ 0 ∧ f.Splits) := isRealRooted_of_degree_one hf_deg1 have hg_rr : (g ≠ 0 ∧ g.Splits) := isRealRooted_of_degree_one (by lia) obtain ⟨rf, hrf_eq⟩ : ∃ rf, f.roots = {rf} := - Multiset.card_eq_one.mp (by simpa [hf_deg1] using card_roots_of_splits hf_rr.2) + Multiset.card_eq_one.mp (by simpa [hf_deg1] using Polynomial.splits_iff_card_roots.mp hf_rr.2) obtain ⟨rg, hrg_eq⟩ : ∃ rg, g.roots = {rg} := Multiset.card_eq_one.mp (by - simpa [show g.natDegree = 1 by lia] using card_roots_of_splits hg_rr.2) + simpa [show g.natDegree = 1 by lia] using Polynomial.splits_iff_card_roots.mp hg_rr.2) by_cases hle : rf ≤ rg · left exact ⟨hf_rr, hg_rr, [rf], [rg], by simp, by simp, by simp [hrf_eq], diff --git a/RealRooted/PosCombo/Degree.lean b/RealRooted/PosCombo/Degree.lean index fd6dd5264..1440afae2 100644 --- a/RealRooted/PosCombo/Degree.lean +++ b/RealRooted/PosCombo/Degree.lean @@ -23,9 +23,8 @@ lemma natDegree_pos_combo_eq_right_of_natDegree_le {f g : ℝ[X]} (C a * f + C b * g).natDegree = g.natDegree := by rcases lt_or_eq_of_le hdeg with hlt | heq · simpa [natDegree_C_mul ha.ne', natDegree_C_mul hb.ne'] using - (natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - (by simpa [natDegree_C_mul ha.ne', natDegree_C_mul hb.ne'] using hlt) - (hasPosLeadingCoeff_C_mul hb hg_pos) : + (Polynomial.natDegree_add_eq_right_of_natDegree_lt + (by simpa [natDegree_C_mul ha.ne', natDegree_C_mul hb.ne'] using hlt) : (C a * f + C b * g).natDegree = (C b * g).natDegree) · have hsame : (C a * f + C b * g).natDegree = f.natDegree := by simpa [natDegree_C_mul ha.ne', natDegree_C_mul hb.ne'] using diff --git a/RealRooted/ProductFamily.lean b/RealRooted/ProductFamily.lean index b9a133d35..75d29b0bc 100644 --- a/RealRooted/ProductFamily.lean +++ b/RealRooted/ProductFamily.lean @@ -20,9 +20,9 @@ lemma hasNonnegCoeffs_affine_mul {s t : ℝ} (hs : 0 ≤ s) (ht : 0 ≤ t) {p : ℝ[X]} (hp : HasNonnegCoeffs p) : HasNonnegCoeffs ((C s * X + C t) * p) := by have hsXp : HasNonnegCoeffs (C s * (X * p)) := - nonnegCoeffs_C_mul hs hp.X_mul + hasNonnegCoeffs_C_mul hs hp.X_mul have htp : HasNonnegCoeffs (C t * p) := - nonnegCoeffs_C_mul ht hp + hasNonnegCoeffs_C_mul ht hp have hsum : HasNonnegCoeffs (C s * (X * p) + C t * p) := hsXp.add htp grind diff --git a/RealRooted/ProductOrientation.lean b/RealRooted/ProductOrientation.lean index ccf674103..fd97fef6e 100644 --- a/RealRooted/ProductOrientation.lean +++ b/RealRooted/ProductOrientation.lean @@ -63,9 +63,9 @@ lemma eval_cross_le_of_strictInterl_sameDegree_of_nonneg rcases hstrictInterl with ⟨hf, hg, ss, rs, _hss_sorted, _hrs_sorted, hss_eq, hrs_eq, hshape⟩ have hlen_ss : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hlen_rs : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have halt : ListAlternates ss rs := by simp_all have hpair : List.Forall₂ (fun x y : ℝ ↦ x ≤ y) ss rs := listAlternates_forall₂_le halt @@ -95,8 +95,8 @@ lemma eval_cross_le_of_strictInterl_sameDegree_of_nonneg prod_le_prod_of_forall₂_of_nonneg hpair_neg hrs_nonneg hss_nonneg have hflc : 0 < f.leadingCoeff := hfnn.pos_leadingCoeff hf.1 have hglc : 0 < g.leadingCoeff := hgnn.pos_leadingCoeff hg.1 - rw [eval_eq_leadingCoeff_mul_prod_sub hf.2 0, - eval_eq_leadingCoeff_mul_prod_sub hg.2 0, ← hss_eq, ← hrs_eq] + rw [Polynomial.Splits.eval_eq_prod_roots hf.2 0, + Polynomial.Splits.eval_eq_prod_roots hg.2 0, ← hss_eq, ← hrs_eq] simp only [Multiset.map_coe, Multiset.prod_coe] linarith [mul_le_mul_of_nonneg_left hprod (le_of_lt (mul_pos hflc hglc))] diff --git a/RealRooted/QuadraticInterlacingClosure.lean b/RealRooted/QuadraticInterlacingClosure.lean index 24fa1cc1e..449cd1946 100644 --- a/RealRooted/QuadraticInterlacingClosure.lean +++ b/RealRooted/QuadraticInterlacingClosure.lean @@ -139,8 +139,8 @@ private lemma hasNonnegCoeffs_quadraticInterlacingPencil {F G H : ℝ[X]} (hF : HasNonnegCoeffs F) (hG : HasNonnegCoeffs G) (hH : HasNonnegCoeffs H) {a : ℝ} (ha : 0 ≤ a) : HasNonnegCoeffs (quadraticInterlacingPencil F G H a) := - (hH.add (nonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha) hG)).add - (nonnegCoeffs_C_mul (sq_nonneg a) hF) + (hH.add (hasNonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha) hG)).add + (hasNonnegCoeffs_C_mul (sq_nonneg a) hF) /-- The right member in the quadratic closure conclusion. -/ def quadraticInterlacingRight (G H : ℝ[X]) (a : ℝ) : ℝ[X] := @@ -260,7 +260,7 @@ theorem eventually_compactifiedQuadraticInterlacingPencil_card_roots_gt_eq exact hF0 have hp0split : (p 0).Splits := by rw [hp0] - exact DegreeDropReversal.splits_reflect_of_splits hFsplit hF + exact Polynomial.Splits.reflect hFsplit hF have hcoeff : ∀ i, Continuous fun b => (p b).coeff i := fun i => by simpa [p] using continuous_coeff_compactifiedQuadraticInterlacingPencil F G H D i @@ -377,7 +377,7 @@ theorem eventually_reciprocalQuadraticInterlacingPencil_card_roots_gt_eq have hFcount := DegreeDropReversal.card_roots_filter_gt_eq_reflect_compl hFsplit hF0 hF hr hrF hFneg have hreflect_eq := hbreflect - (DegreeDropReversal.splits_reflect_of_splits hbsplit hbdegree) + (Polynomial.Splits.reflect hbsplit hbdegree) change ((reflect D (quadraticInterlacingPencil H G F b)).roots.filter (r⁻¹ < ·)).card = ((reflect D F).roots.filter (r⁻¹ < ·)).card at hreflect_eq lia @@ -1947,11 +1947,11 @@ theorem strictInterl_quadraticInterlacingTangent_pencil_of_pos_natDegree have := hQdegree b hb simp_all have hAnn : HasNonnegCoeffs (quadraticInterlacingTangent F G a) := - hG.add (nonnegCoeffs_C_mul ha.le hF) + hG.add (hasNonnegCoeffs_C_mul ha.le hF) have hAne : quadraticInterlacingTangent F G a ≠ 0 := by simpa [quadraticInterlacingTangent, add_comm] using add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - (nonnegCoeffs_C_mul ha.le hF) hG hGne + (hasNonnegCoeffs_C_mul ha.le hF) hG hGne apply strictInterl_of_iterateTDeriv_neg hAnn (hQnn a ha.le) hAne (hQne a ha.le) D intro eps heps @@ -2028,8 +2028,8 @@ theorem strictInterl_quadraticInterlacingTangent_pencil_of_pos_natDegree intro b hb have hsum : C (2 * b) * G + C (b ^ 2) * H + F ≠ 0 := add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - ((nonnegCoeffs_C_mul (mul_nonneg (by norm_num) hb) hG).add - (nonnegCoeffs_C_mul (sq_nonneg b) hH)) hF hFne + ((hasNonnegCoeffs_C_mul (mul_nonneg (by norm_num) hb) hG).add + (hasNonnegCoeffs_C_mul (sq_nonneg b) hH)) hF hFne simpa [quadraticInterlacingPencil, add_comm, add_left_comm, add_assoc] using hsum have hQrecipDeg : ∀ b : ℝ, @@ -2050,11 +2050,11 @@ theorem strictInterl_quadraticInterlacingTangent_pencil_of_pos_natDegree roots_neg_of_hasNonnegCoeffs_of_coeff_zero_ne (hQεnnRecip b hb) (hQεcoeff0Recip b hb) have hAεnn : HasNonnegCoeffs (quadraticInterlacingTangent Fε Gε a) := - hGεnn.add (nonnegCoeffs_C_mul ha.le hFεnn) + hGεnn.add (hasNonnegCoeffs_C_mul ha.le hFεnn) have hAεne : quadraticInterlacingTangent Fε Gε a ≠ 0 := by simpa [quadraticInterlacingTangent, add_comm] using add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - (nonnegCoeffs_C_mul ha.le hFεnn) hGεnn hGεne + (hasNonnegCoeffs_C_mul ha.le hFεnn) hGεnn hGεne have hAεdeg : (quadraticInterlacingTangent Fε Gε a).natDegree ≤ D := (natDegree_add_le _ _).trans (max_le hGεdeg ((natDegree_C_mul_le _ _).trans hFεdeg)) @@ -2090,11 +2090,11 @@ theorem strictInterl_quadraticInterlacingTangent_pencil have hGne : G ≠ 0 := hFG.2.1.1 have hHne : H ≠ 0 := hGH.2.1.1 have hAnn : HasNonnegCoeffs (quadraticInterlacingTangent F G a) := - hG.add (nonnegCoeffs_C_mul ha.le hF) + hG.add (hasNonnegCoeffs_C_mul ha.le hF) have hAne : quadraticInterlacingTangent F G a ≠ 0 := by simpa [quadraticInterlacingTangent, add_comm] using add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - (nonnegCoeffs_C_mul ha.le hF) hG hGne + (hasNonnegCoeffs_C_mul ha.le hF) hG hGne have hAdeg : (quadraticInterlacingTangent F G a).natDegree = 0 := by apply Nat.eq_zero_of_le_zero calc @@ -2108,8 +2108,8 @@ theorem strictInterl_quadraticInterlacingTangent_pencil have hQne : quadraticInterlacingPencil F G H a ≠ 0 := by have hsum : C (2 * a) * G + C (a ^ 2) * F + H ≠ 0 := add_ne_zero_of_hasNonnegCoeffs_of_right_ne_zero - ((nonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha.le) hG).add - (nonnegCoeffs_C_mul (sq_nonneg a) hF)) hH hHne + ((hasNonnegCoeffs_C_mul (mul_nonneg (by norm_num) ha.le) hG).add + (hasNonnegCoeffs_C_mul (sq_nonneg a) hF)) hH hHne simpa [quadraticInterlacingPencil, add_comm, add_left_comm, add_assoc] using hsum have hQdeg : (quadraticInterlacingPencil F G H a).natDegree = 0 := by diff --git a/RealRooted/QuadraticRoot.lean b/RealRooted/QuadraticRoot.lean index e7dfe4a03..33bcfddda 100644 --- a/RealRooted/QuadraticRoot.lean +++ b/RealRooted/QuadraticRoot.lean @@ -85,7 +85,7 @@ lemma quadraticPoly_not_splits_of_discrim_neg {a b c : ℝ} (ha : a ≠ 0) ⟨x, by simpa using hx⟩ /-- Splitting criterion for a real quadratic polynomial. -/ -lemma quadraticPoly_splits_iff_discrim_nonneg {a b c : ℝ} (ha : a ≠ 0) : +private lemma quadraticPoly_splits_iff_discrim_nonneg {a b c : ℝ} (ha : a ≠ 0) : ((C a * X ^ 2 + C b * X + C c) : ℝ[X]).Splits ↔ 0 ≤ discrim a b c := by refine ⟨fun hsplit => ?_, quadraticPoly_splits_of_discrim_nonneg ha⟩ by_contra hneg @@ -152,26 +152,12 @@ theorem splits_of_natDegree_eq_two_of_discrim_nonneg {p : ℝ[X]} (h : p.natDegr (Polynomial.degree_le_of_natDegree_le h.le)] exact quadraticPoly_splits_of_discrim_nonneg ha hd -/-- A real polynomial of degree at most two splits when its discriminant is nonnegative; -degenerate cases (`coeff 2 = 0`) are of degree at most one. -/ -theorem splits_of_natDegree_le_two_of_discrim_nonneg {p : ℝ[X]} (h : p.natDegree ≤ 2) - (hd : 0 ≤ discrim (p.coeff 2) (p.coeff 1) (p.coeff 0)) : p.Splits := by - rcases eq_or_ne (p.coeff 2) 0 with h2 | h2 - · refine Polynomial.Splits.of_natDegree_le_one ?_ - rw [natDegree_le_iff_coeff_eq_zero] - intro N hN - by_cases hN2 : N = 2 - · subst hN2 - exact h2 - · exact coeff_eq_zero_of_natDegree_lt (by lia) - · exact splits_of_natDegree_eq_two_of_discrim_nonneg - (le_antisymm h (Polynomial.le_natDegree_of_ne_zero h2)) hd - /-- The quadratic `C a + C b * X + C c * X ^ 2` splits when `0 ≤ b ^ 2 - 4 * c * a`. -/ theorem splits_C_add_C_mul_X_add_C_mul_X_sq {a b c : ℝ} (h : 0 ≤ b ^ 2 - 4 * c * a) : (C a + C b * X + C c * X ^ 2 : ℝ[X]).Splits := by - refine splits_of_natDegree_le_two_of_discrim_nonneg (by compute_degree) ?_ - simpa [discrim, coeff_X_pow] using h + simpa [add_comm, add_left_comm, add_assoc] using + quadraticPoly_splits_of_discrim_nonneg_or_linear + (a := c) (b := b) (c := a) (by simpa [discrim] using h) /-- A palindromic quartic `a + b X + c X² + b X³ + a X⁴` with `a > 0` splits when the quadratic `a y² + b y + (c - 2a)` in `y = X + 1/X` has both roots at most `-2`, that is, when `4a ≤ b`, diff --git a/RealRooted/ReciprocalShift/ProperPosition.lean b/RealRooted/ReciprocalShift/ProperPosition.lean index 4fc576a61..e7f50f224 100644 --- a/RealRooted/ReciprocalShift/ProperPosition.lean +++ b/RealRooted/ReciprocalShift/ProperPosition.lean @@ -54,9 +54,9 @@ theorem reciprocalShift_reverses_strictInterl · grind refine ⟨hrecipQ, hrecipP, SSout, RSout, hSSsorted, hRSsorted, hSSroots, hRSroots, ?_⟩ have hss_length : ss.length = p.natDegree := by - rw [← Multiset.coe_card, hss_roots, card_roots_of_splits hp_splits] + rw [← Multiset.coe_card, hss_roots, Polynomial.splits_iff_card_roots.mp hp_splits] have hrs_length : rs.length = q.natDegree := by - rw [← Multiset.coe_card, hrs_roots, card_roots_of_splits hq_splits] + rw [← Multiset.coe_card, hrs_roots, Polynomial.splits_iff_card_roots.mp hq_splits] set ssneg := ss.filter (fun r ↦ decide (r ≠ 0)) with hssneg set rsneg := rs.filter (fun r ↦ decide (r ≠ 0)) with hrsneg set zp := ss.count (0 : ℝ) with hzp diff --git a/RealRooted/ReflectedRootCountLocalConstancy.lean b/RealRooted/ReflectedRootCountLocalConstancy.lean index 7331dfbe2..5c0cd92c6 100644 --- a/RealRooted/ReflectedRootCountLocalConstancy.lean +++ b/RealRooted/ReflectedRootCountLocalConstancy.lean @@ -47,7 +47,7 @@ theorem rightFamily_card_roots_Ioo_zero_eq_zero_param_of_degree_bound (reflect N f + C η * reflect N g).Splits := by intro η hη rw [← reflect_add_C_mul] - exact splits_reflect_of_splits (hsplit η hη) (hN η hη) + exact Polynomial.Splits.reflect (hsplit η hη) (hN η hη) have hreflect_not_root : ∀ η ∈ Set.Icc (0 : ℝ) μ, ¬ (reflect N f + C η * reflect N g).IsRoot b⁻¹ := by intro η hη diff --git a/RealRooted/RootContinuity.lean b/RealRooted/RootContinuity.lean index 5db9bfbff..81fb8c81c 100644 --- a/RealRooted/RootContinuity.lean +++ b/RealRooted/RootContinuity.lean @@ -24,7 +24,7 @@ namespace RealRooted /-- A nonzero right-pencil parameter can be inverted by scaling: `f + μ g` is `μ` times `g + μ⁻¹ f`. -/ -theorem add_right_eq_C_mul_add_left_inv +private theorem add_right_eq_C_mul_add_left_inv {f g : ℝ[X]} {μ : ℝ} (hμ : μ ≠ 0) : f + C μ * g = C μ * (g + C μ⁻¹ * f) := by rw [mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hμ, C_1, one_mul, @@ -70,7 +70,7 @@ lemma coeff_norm_le_coeffSumRange (p : ℝ[X]) (i : ℕ) : exact coeffSumRange_nonneg p /-- Coefficient difference for the affine perturbation `f + μ g`. -/ -lemma norm_coeff_sub_add_C_mul (f g : ℝ[X]) (μ : ℝ) (i : ℕ) : +private lemma norm_coeff_sub_add_C_mul (f g : ℝ[X]) (μ : ℝ) (i : ℕ) : ‖(f + C μ * g).coeff i - f.coeff i‖ = ‖μ * g.coeff i‖ := by simp [Polynomial.coeff_add, Polynomial.coeff_C_mul] @@ -105,7 +105,7 @@ theorem exists_complex_aroot_near_of_isRealRooted_of_monic_of_coeff_close /-- Uniform coefficient control for normalized left-family perturbations: `(1/(t+1)) * (t f + g)` is coefficientwise `O((t+1)⁻¹)` away from `f`. -/ -lemma norm_coeff_sub_normalized_left_family_le +private lemma norm_coeff_sub_normalized_left_family_le (f g : ℝ[X]) {t : ℝ} (ht : 0 < t) : ∀ i : ℕ, ‖(C (t + 1)⁻¹ * (C t * f + g)).coeff i - f.coeff i‖ ≤ @@ -127,7 +127,7 @@ lemma norm_coeff_sub_normalized_left_family_le _ = (t + 1)⁻¹ * (coeffSumRange f + coeffSumRange g) := by ring /-- Strict coefficient control from an explicit scalar bound. -/ -lemma norm_coeff_sub_normalized_left_family_lt +private lemma norm_coeff_sub_normalized_left_family_lt (f g : ℝ[X]) {t ε : ℝ} (ht : 0 < t) (hbound : (t + 1)⁻¹ * (coeffSumRange f + coeffSumRange g) < ε) : @@ -233,18 +233,6 @@ theorem exists_complex_aroot_near_in_left_family simpa [q, Polynomial.aroots_C_mul _ (inv_ne_zero ht1_ne)] using hw_qroot grind -/-- Any complex algebraic root of a real-rooted polynomial over `ℝ` has zero -imaginary part. -/ -lemma im_eq_zero_of_mem_aroots_of_isRealRooted - {p : ℝ[X]} (hp_ne : p ≠ 0) (hp_splits : p.Splits) {z : ℂ} - (hz : z ∈ p.aroots ℂ) : - z.im = 0 := by - have hz_root : (p.map (algebraMap ℝ ℂ)).IsRoot z := by simp_all - have hz_range : z ∈ (algebraMap ℝ ℂ).range := - hp_splits.mem_range_of_isRoot hp_ne hz_root - rcases hz_range with ⟨r, rfl⟩ - simp - /-- A real polynomial splits if all of its complex roots have zero imaginary part. -/ theorem splits_of_forall_aeval_im_eq_zero {p : ℝ[X]} @@ -264,7 +252,7 @@ theorem im_eq_zero_of_aeval_eq_zero {p : ℝ[X]} (hp : p ≠ 0) (hs : p.Splits) simp /-- If `(1 - u²) / u` is real for nonzero `u`, then `-u²` is real. -/ -theorem neg_sq_im_eq_zero_of_substitution_real {u : ℂ} (hu : u ≠ 0) +private theorem neg_sq_im_eq_zero_of_substitution_real {u : ℂ} (hu : u ≠ 0) (hreal : ((1 - u ^ 2) / u).im = 0) : (-(u ^ 2)).im = 0 := by rw [show (1 - u ^ 2) / u = u⁻¹ - u by field_simp, Complex.sub_im, @@ -329,8 +317,10 @@ theorem splits_of_monic_of_coeff_approx {f : ℝ[X]} (hf : f.Monic) obtain ⟨w, hwmem, hwdist⟩ := exists_complex_aroot_near_of_isRealRooted_of_monic_of_coeff_close hε hzeval hf hgmonic hgdeg hgcoeff hgsplits - have hwim : w.im = 0 := - im_eq_zero_of_mem_aroots_of_isRealRooted hgmonic.ne_zero hgsplits hwmem + have hwroot : (g.map (algebraMap ℝ ℂ)).IsRoot w := by simp_all + have hwim : w.im = 0 := by + rcases hgsplits.mem_range_of_isRoot hgmonic.ne_zero hwroot with ⟨r, rfl⟩ + simp have hrootbound : (((f.natDegree : ℝ) + 1) * ε) ^ ((f.natDegree : ℝ)⁻¹) < q := by rw [Real.rpow_inv_lt_iff_of_pos (by positivity) hq.le (by exact_mod_cast hdpos)] @@ -441,7 +431,7 @@ theorem card_roots_filter_gt_eq_of_no_isRoot_Ioc fun hx' => lt_of_le_of_lt hab hx'⟩ /-- Additive threshold decomposition of the lower root count. -/ -theorem card_roots_filter_le_add_card_Ioc_eq +private theorem card_roots_filter_le_add_card_Ioc_eq {p : ℝ[X]} {a b : ℝ} (hab : a ≤ b) : (p.roots.filter (· ≤ a)).card + (p.roots.filter (fun x => a < x ∧ x ≤ b)).card diff --git a/RealRooted/RootCountFinite.lean b/RealRooted/RootCountFinite.lean index 972c94f8c..1a341ea9b 100644 --- a/RealRooted/RootCountFinite.lean +++ b/RealRooted/RootCountFinite.lean @@ -197,7 +197,7 @@ theorem card_filter_gt_le_of_rel_abs_sub_lt_of_gt_sep /-- Under a proximity matching, target roots above a threshold can only come from source roots above that threshold or from source roots exactly at the threshold, provided all other source roots are separated from the threshold. -/ -theorem card_filter_gt_le_add_card_filter_eq_of_rel_abs_sub_lt +private theorem card_filter_gt_le_add_card_filter_eq_of_rel_abs_sub_lt {s t : Multiset ℝ} {x δ : ℝ} (hsep : ∀ r ∈ s, r ≠ x → δ ≤ |r - x|) (hmatch : Multiset.Rel (fun r q => |q - r| < δ) s t) : diff --git a/RealRooted/RootCounting/SignChanges.lean b/RealRooted/RootCounting/SignChanges.lean index 1c5a4704d..fedf2b828 100644 --- a/RealRooted/RootCounting/SignChanges.lean +++ b/RealRooted/RootCounting/SignChanges.lean @@ -36,7 +36,7 @@ theorem splits_of_strict_sign_changes {p : ℝ[X]} {rs : List ℝ} rw [Multiset.le_iff_subset (Multiset.coe_nodup.mpr hus_nodup)] intro r hr simp_all - apply RealRooted.splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr apply le_antisymm (card_roots' p) calc p.natDegree = us.length := by lia diff --git a/RealRooted/RootVieta/Newton.lean b/RealRooted/RootVieta/Newton.lean index f7b81f2e0..56a7beb75 100644 --- a/RealRooted/RootVieta/Newton.lean +++ b/RealRooted/RootVieta/Newton.lean @@ -39,7 +39,7 @@ indices above the degree, where both sides vanish. -/ theorem reverse_roots_esymm_eq_coeff_div {p : K[X]} (hp : p.Splits) (h0 : p.coeff 0 ≠ 0) (k : ℕ) : p.reverse.roots.esymm k = (-1 : K) ^ k * p.coeff k / p.coeff 0 := by - have hqsplit : p.reverse.Splits := DegreeDropReversal.splits_reverse hp + have hqsplit : p.reverse.Splits := Polynomial.Splits.reverse hp have hqdeg : p.reverse.natDegree = p.natDegree := by rw [Polynomial.reverse_natDegree, Polynomial.natTrailingDegree_eq_zero.mpr (Or.inr h0)] diff --git a/RealRooted/SameDegreeCubicRootCount.lean b/RealRooted/SameDegreeCubicRootCount.lean index a3f93d020..5d252fc6b 100644 --- a/RealRooted/SameDegreeCubicRootCount.lean +++ b/RealRooted/SameDegreeCubicRootCount.lean @@ -19,7 +19,7 @@ theorem exists_roots_triple_of_splits_natDegree_three {f : ℝ[X]} ∃ a b c : ℝ, a ≤ b ∧ b ≤ c ∧ f.roots = {a, b, c} ∧ f = C f.leadingCoeff * ((X - C a) * (X - C b) * (X - C c)) := by let rs := f.roots.sort (· ≤ ·) - have hrs_len : rs.length = 3 := by simp [rs, card_roots_of_splits hf, hdeg] + have hrs_len : rs.length = 3 := by simp [rs, Polynomial.splits_iff_card_roots.mp hf, hdeg] obtain ⟨a, b, c, hrs⟩ := List.length_eq_three.mp hrs_len have hrs_sorted : rs.Pairwise (· ≤ ·) := by simp [rs] have hsorted : ([a, b, c] : List ℝ).Pairwise (· ≤ ·) := by simp_all @@ -50,7 +50,7 @@ theorem exists_roots_quadruple_of_splits_natDegree_four {f : ℝ[X]} f = C f.leadingCoeff * ((X - C a) * (X - C b) * (X - C c) * (X - C d)) := by let rs := f.roots.sort (· ≤ ·) - have hrs_len : rs.length = 4 := by simp [rs, card_roots_of_splits hf, hdeg] + have hrs_len : rs.length = 4 := by simp [rs, Polynomial.splits_iff_card_roots.mp hf, hdeg] obtain ⟨a, b, c, d, hrs⟩ := List.length_eq_four.mp hrs_len have hrs_sorted : rs.Pairwise (· ≤ ·) := by simp [rs] have hsorted : ([a, b, c, d] : List ℝ).Pairwise (· ≤ ·) := by simpa [hrs] using hrs_sorted diff --git a/RealRooted/SameDegreeDerivative.lean b/RealRooted/SameDegreeDerivative.lean index 43c0abcef..418f8fcfa 100644 --- a/RealRooted/SameDegreeDerivative.lean +++ b/RealRooted/SameDegreeDerivative.lean @@ -29,7 +29,7 @@ theorem le_roots_derivative_of_le_roots {p : ℝ[X]} {c : ℝ} have hs_ss : s ∈ ss := Multiset.mem_coe.mp (by simp_all) have hrs_ne : rs ≠ [] := by rintro rfl - have hcard : p.roots.card = p.natDegree := card_roots_of_splits hp + have hcard : p.roots.card = p.natDegree := Polynomial.splits_iff_card_roots.mp hp have : (0 : ℕ) = p.roots.card := by rw [← hrs_eq] simp @@ -82,7 +82,7 @@ theorem lt_roots_derivative_of_lt_roots {p : ℝ[X]} {u : ℝ} have hs_ss : s ∈ ss := Multiset.mem_coe.mp (by simp_all) have hrs_ne : rs ≠ [] := by rintro rfl - have hcard : p.roots.card = p.natDegree := card_roots_of_splits hp + have hcard : p.roots.card = p.natDegree := Polynomial.splits_iff_card_roots.mp hp have : (0 : ℕ) = p.roots.card := by rw [← hrs_eq] simp @@ -110,7 +110,7 @@ theorem roots_derivative_lt_of_roots_lt {p : ℝ[X]} {v : ℝ} have hs_ss : s ∈ ss := Multiset.mem_coe.mp (by simp_all) have hrs_ne : rs ≠ [] := by rintro rfl - have hcard : p.roots.card = p.natDegree := card_roots_of_splits hp + have hcard : p.roots.card = p.natDegree := Polynomial.splits_iff_card_roots.mp hp have : (0 : ℕ) = p.roots.card := by rw [← hrs_eq] simp diff --git a/RealRooted/SamePhaseStability/Nonnegative.lean b/RealRooted/SamePhaseStability/Nonnegative.lean index 9dddc926e..a270d6e7a 100644 --- a/RealRooted/SamePhaseStability/Nonnegative.lean +++ b/RealRooted/SamePhaseStability/Nonnegative.lean @@ -32,7 +32,7 @@ theorem commonPhaseRestriction_hasNonnegCoeffs {σ : Type*} unfold Finsupp.prod apply hasNonnegCoeffs_finsetProd intro i hi - exact (nonnegCoeffs_C_mul (hwt i) hasNonnegCoeffs_X).pow (d i) + exact (hasNonnegCoeffs_C_mul (hwt i) hasNonnegCoeffs_X).pow (d i) end diff --git a/RealRooted/SequenceClosure.lean b/RealRooted/SequenceClosure.lean index da0aa0fd2..6ed9c070e 100644 --- a/RealRooted/SequenceClosure.lean +++ b/RealRooted/SequenceClosure.lean @@ -210,7 +210,7 @@ theorem reverse_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) : rcases hp with hp | hp · left simp [hp] - · exact Or.inr (DegreeDropReversal.splits_reverse hp) + · exact Or.inr (Polynomial.Splits.reverse hp) /-- Consume a reverse zero-aware real-rootedness certificate. -/ theorem eq_zero_or_splits_of_reverse {p : ℝ[X]} @@ -218,7 +218,7 @@ theorem eq_zero_or_splits_of_reverse {p : ℝ[X]} p = 0 ∨ p.Splits := by rcases hp with hp | hp · exact Or.inl (Polynomial.reverse_eq_zero.mp hp) - · exact Or.inr (DegreeDropReversal.splits_of_reverse hp) + · exact Or.inr (Polynomial.Splits.of_reverse hp) /-- Reflect transport for zero-aware real-rootedness certificates. -/ theorem reflect_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) {N : ℕ} @@ -227,7 +227,7 @@ theorem reflect_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) {N : rcases hp with hp | hp · left simp [hp] - · exact Or.inr (DegreeDropReversal.splits_reflect_of_splits hp hN) + · exact Or.inr (Polynomial.Splits.reflect hp hN) /-- Degree-padded reverse transport for zero-aware real-rootedness certificates. -/ theorem X_pow_mul_reverse_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Splits) @@ -237,7 +237,7 @@ theorem X_pow_mul_reverse_eq_zero_or_splits {p : ℝ[X]} (hp : p = 0 ∨ p.Split rcases hp with hp | hp · left simp [hp] - · exact Or.inr (DegreeDropReversal.splits_X_pow_mul_reverse hp N) + · exact Or.inr (Polynomial.Splits.X_pow_mul_reverse hp N) /-- Divide out a zero root in a zero-aware real-rootedness certificate. -/ theorem divX_eq_zero_or_splits_of_coeff_zero {p : ℝ[X]} (h0 : p.coeff 0 = 0) @@ -261,19 +261,19 @@ theorem eq_zero_or_splits_of_divX {p : ℝ[X]} (h0 : p.coeff 0 = 0) theorem reverse_isRealRooted {p : ℝ[X]} (hp : p ≠ 0 ∧ p.Splits) : p.reverse ≠ 0 ∧ p.reverse.Splits := ⟨fun h => hp.1 (Polynomial.reverse_eq_zero.mp h), - DegreeDropReversal.splits_reverse hp.2⟩ + Polynomial.Splits.reverse hp.2⟩ /-- Consume a reverse nonzero real-rootedness certificate. -/ theorem isRealRooted_of_reverse {p : ℝ[X]} (hp : p.reverse ≠ 0 ∧ p.reverse.Splits) : p ≠ 0 ∧ p.Splits := - ⟨fun h => hp.1 (by simp [h]), DegreeDropReversal.splits_of_reverse hp.2⟩ + ⟨fun h => hp.1 (by simp [h]), Polynomial.Splits.of_reverse hp.2⟩ /-- Reflect transport for nonzero real-rootedness certificates. -/ theorem reflect_isRealRooted {p : ℝ[X]} (hp : p ≠ 0 ∧ p.Splits) {N : ℕ} (hN : p.natDegree ≤ N) : (reflect N p) ≠ 0 ∧ (reflect N p).Splits := ⟨fun h => hp.1 (Polynomial.reflect_eq_zero_iff.mp h), - DegreeDropReversal.splits_reflect_of_splits hp.2 hN⟩ + Polynomial.Splits.reflect hp.2 hN⟩ /-- Degree-padded reverse transport for nonzero real-rootedness certificates. -/ theorem X_pow_mul_reverse_isRealRooted {p : ℝ[X]} (hp : p ≠ 0 ∧ p.Splits) @@ -282,7 +282,7 @@ theorem X_pow_mul_reverse_isRealRooted {p : ℝ[X]} (hp : p ≠ 0 ∧ p.Splits) (X ^ (N - p.natDegree) * p.reverse).Splits := ⟨mul_ne_zero (pow_ne_zero _ Polynomial.X_ne_zero) (fun h => hp.1 (Polynomial.reverse_eq_zero.mp h)), - DegreeDropReversal.splits_X_pow_mul_reverse hp.2 N⟩ + Polynomial.Splits.X_pow_mul_reverse hp.2 N⟩ /-- Divide out a zero root in a nonzero real-rootedness certificate. -/ theorem divX_isRealRooted_of_coeff_zero {p : ℝ[X]} (h0 : p.coeff 0 = 0) @@ -649,7 +649,8 @@ theorem mul_eq_zero_or_splits_of_eq_zero_or_splits_pair_sequence (hP : ∀ n : Nat, (A n = 0 ∨ (A n).Splits) ∧ (B n = 0 ∨ (B n).Splits)) : ∀ n : Nat, A n * B n = 0 ∨ (A n * B n).Splits := - fun n => mul_eq_zero_or_splits (hP n).1 (hP n).2 + fun n => Or.inr (((hP n).1.elim (fun h => h ▸ Splits.zero) id).mul + ((hP n).2.elim (fun h => h ▸ Splits.zero) id)) /-- Row-wise swapped product transport for zero-aware pair-sequences. -/ theorem swap_mul_eq_zero_or_splits_of_eq_zero_or_splits_pair_sequence @@ -657,6 +658,7 @@ theorem swap_mul_eq_zero_or_splits_of_eq_zero_or_splits_pair_sequence (hP : ∀ n : Nat, (A n = 0 ∨ (A n).Splits) ∧ (B n = 0 ∨ (B n).Splits)) : ∀ n : Nat, B n * A n = 0 ∨ (B n * A n).Splits := - fun n => mul_eq_zero_or_splits (hP n).2 (hP n).1 + fun n => Or.inr (((hP n).2.elim (fun h => h ▸ Splits.zero) id).mul + ((hP n).1.elim (fun h => h ▸ Splits.zero) id)) end RealRooted diff --git a/RealRooted/ShiftLemma.lean b/RealRooted/ShiftLemma.lean index e3e0f3651..1d978a0e6 100644 --- a/RealRooted/ShiftLemma.lean +++ b/RealRooted/ShiftLemma.lean @@ -85,7 +85,7 @@ lemma shift_natDegree_of_same_degree {f h : ℝ[X]} have hXh_pos := hasPosLeadingCoeff_X_sub_C_mul (r := (1 : ℝ)) hh_pos have hlt : f.natDegree < ((X - C 1) * h).natDegree := by lia constructor - · exact natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hlt hXh_pos ▸ hXh_deg + · exact Polynomial.natDegree_add_eq_right_of_natDegree_lt hlt ▸ hXh_deg · exact hasPosLeadingCoeff_add_of_natDegree_lt_right hlt hXh_pos /-! ## Same-degree case -/ @@ -169,9 +169,9 @@ theorem strictInterl_shift StrictInterl f (f + (X - C 1) * h) := by obtain ⟨_, _, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, hshape⟩ := hstrictInterl have hss_len : ss.length = h.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hh_splits] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hh_splits] have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] rcases hshape with ⟨hdiffby1, hint⟩ | ⟨hsamedeg, halt⟩ · have hdeg : h.natDegree + 1 = f.natDegree := by lia have hinterl : Interlaces h f := diff --git a/RealRooted/SortedRoots/Exhibited.lean b/RealRooted/SortedRoots/Exhibited.lean index 254c24995..7622633c7 100644 --- a/RealRooted/SortedRoots/Exhibited.lean +++ b/RealRooted/SortedRoots/Exhibited.lean @@ -54,7 +54,7 @@ theorem splits_and_rootSeq_eq_of_exhibited {p : ℝ[X]} {n : ℕ} p.Splits ∧ ∀ i, i < n → rootSeq p i = x i := by classical have hcard := card_roots_eq_natDegree_of_exhibited hdeg hp hmono hroot - have hsp : p.Splits := splits_of_card_roots (by lia) + have hsp : p.Splits := Polynomial.splits_iff_card_roots.mpr (by lia) refine ⟨hsp, ?_⟩ have hlen : (rootMags p).length = n := by rw [rootMags_length, hcard, hdeg] diff --git a/RealRooted/SuccDegreeLeftEndpoint.lean b/RealRooted/SuccDegreeLeftEndpoint.lean index 5f11a463d..e367fa318 100644 --- a/RealRooted/SuccDegreeLeftEndpoint.lean +++ b/RealRooted/SuccDegreeLeftEndpoint.lean @@ -461,7 +461,7 @@ theorem splits_right_of_closedSegmentIcc_family_of_succDegree {f g : ℝ[X]} These bundle the closed-segment endpoint-splitting facts with the corresponding full real root-count equality `roots.card = natDegree` (via -`card_roots_of_splits`), the form consumed by the root-count leg of the direct +`Polynomial.splits_iff_card_roots.mp`), the form consumed by the root-count leg of the direct #42 route. They introduce no new mathematics. -/ /-- Root-count package for the lower-degree endpoint: under the succ-degree @@ -472,7 +472,7 @@ theorem left_card_roots_of_succDegree {f g : ℝ[X]} (hfg : PosComboRealRooted f g) (hsucc : g.natDegree = f.natDegree + 1) : f.roots.card = f.natDegree := - card_roots_of_splits + Polynomial.splits_iff_card_roots.mp (hfg.left_splits_of_succDegree hf_pos hg_pos hsucc) /-- Root-count package for the higher-degree endpoint. -/ @@ -481,7 +481,7 @@ theorem right_card_roots_of_succDegree {f g : ℝ[X]} (hfg : PosComboRealRooted f g) (hsucc : f.natDegree = g.natDegree + 1) : g.roots.card = g.natDegree := - card_roots_of_splits + Polynomial.splits_iff_card_roots.mp (hfg.right_splits_of_succDegree hf_pos hg_pos hsucc) /-- Root-count package for the lower-degree endpoint, packaged as the @@ -509,7 +509,7 @@ theorem left_card_roots_of_closedSegmentIcc_family_of_succDegree {f g : ℝ[X]} (hf_pos : HasPosLeadingCoeff f) (hg_pos : HasPosLeadingCoeff g) (hsucc : g.natDegree = f.natDegree + 1) : f.roots.card = f.natDegree := - card_roots_of_splits + Polynomial.splits_iff_card_roots.mp (splits_of_closedSegmentIcc_family_of_succDegree hfamily hf_pos hg_pos hsucc) /-- Closed-segment (inclusive) root-count package at the higher-degree endpoint. -/ @@ -519,7 +519,7 @@ theorem right_card_roots_of_closedSegmentIcc_family_of_succDegree {f g : ℝ[X]} (hf_pos : HasPosLeadingCoeff f) (hg_pos : HasPosLeadingCoeff g) (hsucc : f.natDegree = g.natDegree + 1) : g.roots.card = g.natDegree := - card_roots_of_splits + Polynomial.splits_iff_card_roots.mp (splits_right_of_closedSegmentIcc_family_of_succDegree hfamily hf_pos hg_pos hsucc) diff --git a/RealRooted/SymmetricDecomposition/Decomposition.lean b/RealRooted/SymmetricDecomposition/Decomposition.lean index 14fbe9ca0..ec5ccd4b7 100644 --- a/RealRooted/SymmetricDecomposition/Decomposition.lean +++ b/RealRooted/SymmetricDecomposition/Decomposition.lean @@ -173,19 +173,14 @@ lemma idTransform_X_mul_of_natDegree_le_two_pred {d : ℕ} {p : ℝ[X]} idTransform_of_natDegree_le_pred (d := d - 1) (by lia) (by lia) theorem strictInterl_iff_strictInterl_mul_X_both_of_hasNonnegCoeffs {f g : ℝ[X]} - (hfnn : HasNonnegCoeffs f) (hgnn : HasNonnegCoeffs g) : + (_hfnn : HasNonnegCoeffs f) (_hgnn : HasNonnegCoeffs g) : StrictInterl f g ↔ StrictInterl (X * f) (X * g) := by constructor · intro h - have hf_nonpos : ∀ r ∈ f.roots, r ≤ 0 := roots_nonpos_of_hasNonnegCoeffs hfnn - have hg_nonpos : ∀ r ∈ g.roots, r ≤ 0 := roots_nonpos_of_hasNonnegCoeffs hgnn - exact (StrictInterl.mul_X_both_iff_of_roots_nonpos hf_nonpos hg_nonpos).1 h + simpa using h.mul_X_sub_C_both 0 · intro h - have hf_rr : (f ≠ 0 ∧ f.Splits) := isRealRooted_of_X_mul h.1.1 h.1.2 - have hg_rr : (g ≠ 0 ∧ g.Splits) := isRealRooted_of_X_mul h.2.1.1 h.2.1.2 - have hf_nonpos : ∀ r ∈ f.roots, r ≤ 0 := roots_nonpos_of_hasNonnegCoeffs hfnn - have hg_nonpos : ∀ r ∈ g.roots, r ≤ 0 := roots_nonpos_of_hasNonnegCoeffs hgnn - exact (StrictInterl.mul_X_both_iff_of_roots_nonpos hf_nonpos hg_nonpos).2 h + apply StrictInterl.of_mul_X_sub_C_both (r := 0) + simpa using h lemma hasNonnegCoeffs_of_eq_X_mul {p q : ℝ[X]} (hp : HasNonnegCoeffs p) (h : p = X * q) : diff --git a/RealRooted/SymmetricDecomposition/EulerianTransform.lean b/RealRooted/SymmetricDecomposition/EulerianTransform.lean index 9b32effb4..394f3c6f5 100644 --- a/RealRooted/SymmetricDecomposition/EulerianTransform.lean +++ b/RealRooted/SymmetricDecomposition/EulerianTransform.lean @@ -444,14 +444,14 @@ theorem transform_magicExpansion_interl {d : ℕ} {c : ℕ → ℝ} exact Interl.C_mul_right_of_nonneg (hleft j hjn) (hc j hjn) · intro j hj have hjn : j ≤ d := by simpa [Nat.lt_succ_iff] using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (hc j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) + exact hasNonnegCoeffs_C_mul (hc j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) · apply Interl.finsetSum_right_of_nonneg · intro j hj have hjn : j ≤ d := by simpa [Nat.lt_succ_iff] using Finset.mem_range.mp hj exact Interl.C_mul_left_of_nonneg (hright j hjn) (hc j hjn) · intro j hj have hjn : j ≤ d := by simpa [Nat.lt_succ_iff] using Finset.mem_range.mp hj - exact nonnegCoeffs_C_mul (hc j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) + exact hasNonnegCoeffs_C_mul (hc j hjn) (hdirect.nonnegCoeffs _ (hmem j hjn)) end EulerianTransform end RealRooted diff --git a/RealRooted/SymmetricDecomposition/FPolynomial.lean b/RealRooted/SymmetricDecomposition/FPolynomial.lean index 69b27a233..da9d8231f 100644 --- a/RealRooted/SymmetricDecomposition/FPolynomial.lean +++ b/RealRooted/SymmetricDecomposition/FPolynomial.lean @@ -66,7 +66,7 @@ lemma hasNonnegCoeffs_fPolynomial {d : ℕ} {h : ℝ[X]} (hh : HasNonnegCoeffs h unfold fPolynomial apply hasNonnegCoeffs_finsetSum intro k _ - simpa [mul_assoc] using nonnegCoeffs_C_mul (hh k) + simpa [mul_assoc] using hasNonnegCoeffs_C_mul (hh k) ((hasNonnegCoeffs_X.pow k).mul (hasNonnegCoeffs_X_add_one.pow (d - k))) @@ -341,7 +341,7 @@ theorem roots_fPolynomial_natDegree_eq_map {p : ℝ[X]} (hp : p ≠ 0) (hs : p.S rw [hpC] simp [fPolynomial] · have hroots_pos : 0 < p.roots.card := by - rw [card_roots_of_splits hp.2, hpdeg] + rw [Polynomial.splits_iff_card_roots.mp hp.2, hpdeg] lia obtain ⟨r, hr_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hr_root : p.IsRoot r := (mem_roots hp.1).mp hr_mem @@ -372,8 +372,8 @@ theorem roots_fPolynomial_natDegree_eq_map {p : ℝ[X]} (hp : p ≠ 0) (hs : p.S have hqf_ne : fPolynomial q.natDegree q ≠ 0 := fPolynomial_ne_zero_of_ne_zero_of_not_isRoot_one hq1 have hqf_splits : (fPolynomial q.natDegree q).Splits := by - apply splits_of_card_roots - rw [ihq, Multiset.card_map, card_roots_of_splits hq_rr.2, + apply Polynomial.splits_iff_card_roots.mpr + rw [ihq, Multiset.card_map, Polynomial.splits_iff_card_roots.mp hq_rr.2, natDegree_fPolynomial_natDegree hq1] have h1r_ne : 1 - r ≠ 0 := by grind have hroots_f : @@ -535,14 +535,14 @@ private lemma StrictInterl.fPolynomial_natDegree_of_root_property {P : ℝ → P have hgdeg := natDegree_fPolynomial_natDegree hg₁ have hfr : fPolynomial f.natDegree f ≠ 0 ∧ (fPolynomial f.natDegree f).Splits := by refine ⟨fPolynomial_ne_zero_of_ne_zero_of_not_isRoot_one hf₁, ?_⟩ - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr rw [roots_fPolynomial_natDegree_eq_map hf₀.1 hf₀.2 hf₁, Multiset.card_map, - card_roots_of_splits hf₀.2, hfdeg] + Polynomial.splits_iff_card_roots.mp hf₀.2, hfdeg] have hgr : fPolynomial g.natDegree g ≠ 0 ∧ (fPolynomial g.natDegree g).Splits := by refine ⟨fPolynomial_ne_zero_of_ne_zero_of_not_isRoot_one hg₁, ?_⟩ - apply splits_of_card_roots + apply Polynomial.splits_iff_card_roots.mpr rw [roots_fPolynomial_natDegree_eq_map hg₀.1 hg₀.2 hg₁, Multiset.card_map, - card_roots_of_splits hg₀.2, hgdeg] + Polynomial.splits_iff_card_roots.mp hg₀.2, hgdeg] have hss_bound : ∀ r ∈ ss, P r := by intro r hr exact hf r (hss_eq ▸ Multiset.mem_coe.mpr hr) @@ -727,7 +727,7 @@ theorem splits_fPolynomial {d : ℕ} {p : ℝ[X]} (hpdeg : p.natDegree ≤ d) (h by_cases hp0 : p = 0 · simp [hp0] have hcard : 0 < p.roots.card := by - rw [card_roots_of_splits hp] + rw [Polynomial.splits_iff_card_roots.mp hp] lia obtain ⟨r, hr⟩ := Multiset.card_pos_iff_exists_mem.mp hcard obtain ⟨q, hq⟩ := dvd_iff_isRoot.mpr ((mem_roots hp0).mp hr) @@ -803,7 +803,7 @@ private theorem isRealRooted_of_fPolynomial_natDegree_roots_gt_neg_one by_cases hn : n = 0 · exact isRealRooted_of_deg_zero hp0 (by lia) · have hroots_pos : 0 < (fPolynomial n p).roots.card := by - rw [card_roots_of_splits hq_rr.2, hqdeg] + rw [Polynomial.splits_iff_card_roots.mp hq_rr.2, hqdeg] lia obtain ⟨x, hx_mem⟩ := Multiset.card_pos_iff_exists_mem.mp hroots_pos have hx_root : (fPolynomial n p).IsRoot x := (mem_roots hq_rr.1).mp hx_mem diff --git a/RealRooted/SymmetricDecomposition/FPolynomialInterlacing.lean b/RealRooted/SymmetricDecomposition/FPolynomialInterlacing.lean index 75a9140d7..320894f6a 100644 --- a/RealRooted/SymmetricDecomposition/FPolynomialInterlacing.lean +++ b/RealRooted/SymmetricDecomposition/FPolynomialInterlacing.lean @@ -492,7 +492,7 @@ theorem posComboRealRooted_fPolynomial_of_strictInterl have hcombo_rr : ((C lam * u + C μ * v) ≠ 0 ∧ (C lam * u + C μ * v).Splits) := PosComboRealRooted.of_strictInterl h hu_pos hv_pos hlam hμ have hcombo_nonneg : HasNonnegCoeffs (C lam * u + C μ * v) := - (nonnegCoeffs_C_mul hlam.le hu_nonneg).add (nonnegCoeffs_C_mul hμ.le hv_nonneg) + (hasNonnegCoeffs_C_mul hlam.le hu_nonneg).add (hasNonnegCoeffs_C_mul hμ.le hv_nonneg) have hcombo_deg : (C lam * u + C μ * v).natDegree ≤ d := by have hud' : (C lam * u).natDegree ≤ d := by simpa [Polynomial.natDegree_C_mul hlam.ne'] have hvd' : (C μ * v).natDegree ≤ d := by simpa [Polynomial.natDegree_C_mul hμ.ne'] diff --git a/RealRooted/SymmetricDecomposition/FPolynomialSequence.lean b/RealRooted/SymmetricDecomposition/FPolynomialSequence.lean index c8658f70e..0733f1d4a 100644 --- a/RealRooted/SymmetricDecomposition/FPolynomialSequence.lean +++ b/RealRooted/SymmetricDecomposition/FPolynomialSequence.lean @@ -45,17 +45,17 @@ lemma StrictInterl.of_mul_X_sub_C_left_of_roots_gt ring rcases h with ⟨hxf_rr, hg_rr, ss, rs, hss, hrs, hss_eq, hrs_eq, hshape⟩ have hsslen : ss.length = f.natDegree + 1 := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hxf_rr.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hxf_rr.2] rw [hxfdeg] have hrslen : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] have hss_eq_sort : (↑(f.roots.sort (· ≤ ·)) : Multiset ℝ) = f.roots := Multiset.sort_eq .. let sf := f.roots.sort (· ≤ ·) have hsf : sf.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hsflen : sf.length = f.natDegree := by rw [← Multiset.coe_card, show (↑sf : Multiset ℝ) = f.roots from hss_eq_sort, - card_roots_of_splits hf.2] + Polynomial.splits_iff_card_roots.mp hf.2] have hrootmul : ((X - C r) * f).roots = ({r} : Multiset ℝ) + f.roots := by rw [roots_mul hxf, roots_X_sub_C] have hss_perm : ss.Perm (sf.orderedInsert (· ≤ ·) r) := by @@ -131,9 +131,9 @@ lemma StrictInterl.of_mul_X_sub_C_right_of_roots_ge have hss_is : ss = sf := List.Perm.eq_of_pairwise' hss hsf hss_perm have hrs_is : rs = sg := List.Perm.eq_of_pairwise' hrs hsg hrs_perm have hsf_len : sf.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq_sort, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq_sort, Polynomial.splits_iff_card_roots.mp hf.2] have hsg_len : sg.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq_sort, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq_sort, Polynomial.splits_iff_card_roots.mp hg.2] have hrsg : ∀ s ∈ sg, r ≤ s := by intro s hs have hs' : s ∈ (↑sg : Multiset ℝ) := Multiset.mem_coe.mpr hs diff --git a/RealRooted/SymmetricDecomposition/Theorem26.lean b/RealRooted/SymmetricDecomposition/Theorem26.lean index 4820b2a7d..acd4a6c3c 100644 --- a/RealRooted/SymmetricDecomposition/Theorem26.lean +++ b/RealRooted/SymmetricDecomposition/Theorem26.lean @@ -13,11 +13,6 @@ noncomputable section namespace RealRooted -lemma strictInterl_of_interl_of_ne_zero {f g : ℝ[X]} - (hf : f ≠ 0) (hg : g ≠ 0) (h : Interl f g) : - StrictInterl f g := by - rcases h with rfl | rfl | hstrictInterl <;> lia - private lemma natDegree_add_X_mul_ge_of_hasNonnegCoeffs {a b : ℝ[X]} (ha_nonneg : HasNonnegCoeffs a) @@ -97,9 +92,9 @@ private theorem strictInterl_b_component_of_strictInterl_sum_of_leadingCoeff_eq have hsub_eq : C c * p - X * (C c * b) = C c * a := by grind rw [hsub_eq] at hinterl have hscaled_strictInterl : StrictInterl (C c * b) (C c * a) := - strictInterl_of_interl_of_ne_zero + hinterl.toStrictInterl_of_ne (mul_ne_zero (Polynomial.C_ne_zero.mpr hc_ne) hb0) - (mul_ne_zero (Polynomial.C_ne_zero.mpr hc_ne) ha0) hinterl + (mul_ne_zero (Polynomial.C_ne_zero.mpr hc_ne) ha0) have hback : StrictInterl (C c⁻¹ * (C c * b)) (C c⁻¹ * (C c * a)) := StrictInterl.C_mul_right @@ -140,7 +135,7 @@ theorem BrandenSolus.forward_of_strictInterl_b_a {d : ℕ} {p a b : ℝ[X]} · exact Interl.refl fun _ ↦ ha_rr.2 · exact haxb.toInterl · simp_all - exact strictInterl_of_interl_of_ne_zero ha_rr.1 hp0 (by simp_all) + exact (show Interl a p by simp_all).toStrictInterl_of_ne ha_rr.1 hp0 have hbXb : StrictInterl b (X * b) := strictInterl_mul_X_of_strictInterl_of_nonneg (StrictInterl.refl hb_rr.1 hb_rr.2) hb_nonneg hb_nonneg @@ -153,7 +148,7 @@ theorem BrandenSolus.forward_of_strictInterl_b_a {d : ℕ} {p a b : ℝ[X]} · exact hba.toInterl · exact hbXb.toInterl · simp_all - exact strictInterl_of_interl_of_ne_zero hb_rr.1 hp0 (by simp_all) + exact (show Interl b p by simp_all).toStrictInterl_of_ne hb_rr.1 hp0 have hIda : StrictInterl (a + b) a := by simpa [add_comm, add_left_comm, add_assoc] using (hba.nonneg_combo_right hb_pos ha_pos @@ -167,8 +162,9 @@ theorem BrandenSolus.forward_of_strictInterl_b_a {d : ℕ} {p a b : ℝ[X]} cases t <;> simp [hap.toInterl, hbp.toInterl] · lia have hId0 : idTransform d p ≠ 0 := by simpa [hId_eq] using hIda.1.1 - exact strictInterl_of_interl_of_ne_zero hId0 hp0 (by - simpa [hId_eq, add_comm, add_left_comm, add_assoc] using hinterl) + exact (by + simpa [hId_eq, add_comm, add_left_comm, add_assoc] using hinterl : + Interl (idTransform d p) p).toStrictInterl_of_ne hId0 hp0 lia theorem BrandenSolus.third_equiv_of_natDegree_le @@ -534,7 +530,7 @@ private theorem strictInterl_b_component_of_strictInterl_Id_top_of_right_top have hdeg_lt : b.natDegree < a.natDegree := by lia calc (a + b).natDegree = a.natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg_lt ha_pos + Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg_lt _ = d := ha_top have hdeg_lt : b.natDegree < a.natDegree := by lia have hh_pos : HasPosLeadingCoeff h := by @@ -647,7 +643,7 @@ theorem BrandenSolus.third_converse_of_top_degree rw [hId_eq] calc (a + b).natDegree = a.natDegree := - natDegree_add_eq_left_of_natDegree_lt_of_posLeadingCoeff hdeg_lt ha_pos + Polynomial.natDegree_add_eq_left_of_natDegree_lt hdeg_lt _ = d := ha_top have hh_nonpos : ∀ r ∈ h.roots, r ≤ 0 := roots_nonpos_of_hasNonnegCoeffs hh_nonneg @@ -998,7 +994,7 @@ theorem BrandenSolus.ordered_bridge_converse_of_natDegree_le natDegree_add_eq_of_same_natDegree_of_posLeadingCoeff hdeg_eq ha_pos hb_pos _ = b.natDegree := hdeg_eq · have hdeg_lt : a.natDegree < b.natDegree := lt_of_le_of_ne ha_le hdeg_eq - exact natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hdeg_lt hb_pos + exact Polynomial.natDegree_add_eq_right_of_natDegree_lt hdeg_lt have hh_pos : HasPosLeadingCoeff h := by rw [hId_eq] by_cases hdeg_eq : a.natDegree = b.natDegree diff --git a/RealRooted/Tactic/Examples/RowParityFactorization.lean b/RealRooted/Tactic/Examples/RowParityFactorization.lean index 3d378aaf8..d6b686662 100644 --- a/RealRooted/Tactic/Examples/RowParityFactorization.lean +++ b/RealRooted/Tactic/Examples/RowParityFactorization.lean @@ -317,7 +317,7 @@ private theorem a082649_eq_reverse (n : ℕ) : private theorem a082649_splits (n : ℕ) : (a082649 n).Splits := by rw [a082649_eq_reverse] - exact RealRooted.DegreeDropReversal.splits_reverse (a334009_splits n) + exact Polynomial.Splits.reverse (a334009_splits n) /-- Split-row transfer for the reversed three-lag A082649 presentation. -/ @[rr_row_model] @@ -599,7 +599,7 @@ private theorem shifted049325_nonneg : ∀ n : ℕ, HasNonnegCoeffs (shifted0493 simp_all _ = C (1 / ((n : ℝ) + 4)) * R := by rw [shifted049325_first_order] rw [heq] - exact nonnegCoeffs_C_mul (by positivity) hR + exact hasNonnegCoeffs_C_mul (by positivity) hR private theorem shifted049325_ne_zero (n : ℕ) : shifted049325 n ≠ 0 := by have hudeg : (C (-16 : ℝ) - X).natDegree = 1 := by compute_degree! diff --git a/RealRooted/Tactic/Finish.lean b/RealRooted/Tactic/Finish.lean index e36f97d6d..f51fead30 100644 --- a/RealRooted/Tactic/Finish.lean +++ b/RealRooted/Tactic/Finish.lean @@ -22,6 +22,10 @@ open Lean open Lean.Meta open Lean.Elab.Tactic +private theorem splits_of_eq_zero_or_splits {p : ℝ[X]} (h : p = 0 ∨ p.Splits) : + p.Splits := + h.elim (fun hp => hp ▸ Polynomial.Splits.zero) id + /-- Term form of `rr_lookup`: elaborates to `by rr_lookup`. -/ syntax (name := rr_lookup_term) "rr_lookup_term" : term /-- Term form of `rr_realrooted`: elaborates to `by rr_realrooted`. -/ @@ -819,9 +823,9 @@ macro_rules RealRooted.swap_mul_splits_of_isRealRooted_pair $h, RealRooted.splits_pow_of_isRealRooted $h _, Polynomial.Splits.pow $h _, - RealRooted.DegreeDropReversal.splits_reverse $h, - RealRooted.DegreeDropReversal.splits_of_reverse $h, - RealRooted.DegreeDropReversal.splits_X_pow_mul_reverse $h _, + Polynomial.Splits.reverse $h, + Polynomial.Splits.of_reverse $h, + Polynomial.Splits.X_pow_mul_reverse $h _, (RealRooted.DegreeDropReversal.splits_X_pow_mul_iff _).mpr $h, (RealRooted.DegreeDropReversal.splits_X_pow_mul_iff _).mp $h) | `(tactic| @@ -842,23 +846,23 @@ macro_rules rr_splits_reverse using splits := $h:term) => `(tactic| - exact RealRooted.DegreeDropReversal.splits_reverse $h) + exact Polynomial.Splits.reverse $h) | `(tactic| rr_splits_of_reverse using reverse_splits := $h:term) => `(tactic| - exact RealRooted.DegreeDropReversal.splits_of_reverse $h) + exact Polynomial.Splits.of_reverse $h) | `(tactic| rr_splits_reflect using splits := $h:term, degree_bound := $hN:term) => `(tactic| - exact RealRooted.DegreeDropReversal.splits_reflect_of_splits $h $hN) + exact Polynomial.Splits.reflect $h $hN) | `(tactic| rr_splits_X_pow_mul_reverse using splits := $h:term) => `(tactic| - exact RealRooted.DegreeDropReversal.splits_X_pow_mul_reverse $h _) + exact Polynomial.Splits.X_pow_mul_reverse $h _) | `(tactic| rr_splits_divX using coeff_zero := $h0:term, @@ -914,12 +918,16 @@ macro_rules RealRooted.eq_zero_or_splits_of_isRealRooted $h, RealRooted.left_eq_zero_or_splits_of_eq_zero_or_splits_pair $h, RealRooted.right_eq_zero_or_splits_of_eq_zero_or_splits_pair $h, - (RealRooted.mul_eq_zero_or_splits - (RealRooted.left_eq_zero_or_splits_of_eq_zero_or_splits_pair $h) - (RealRooted.right_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)), - (RealRooted.mul_eq_zero_or_splits - (RealRooted.right_eq_zero_or_splits_of_eq_zero_or_splits_pair $h) - (RealRooted.left_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)), + (Or.inr + ((splits_of_eq_zero_or_splits + (RealRooted.left_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)).mul + (splits_of_eq_zero_or_splits + (RealRooted.right_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)))), + (Or.inr + ((splits_of_eq_zero_or_splits + (RealRooted.right_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)).mul + (splits_of_eq_zero_or_splits + (RealRooted.left_eq_zero_or_splits_of_eq_zero_or_splits_pair $h)))), RealRooted.left_eq_zero_or_splits_of_isRealRooted_pair $h, RealRooted.right_eq_zero_or_splits_of_isRealRooted_pair $h, RealRooted.mul_eq_zero_or_splits_of_isRealRooted_pair $h, @@ -951,12 +959,12 @@ macro_rules $h _), Or.inr $h, Or.inr (Polynomial.Splits.pow $h _), - Or.inr (RealRooted.DegreeDropReversal.splits_reverse $h), - Or.inr (RealRooted.DegreeDropReversal.splits_of_reverse $h), - Or.inr (RealRooted.DegreeDropReversal.splits_X_pow_mul_reverse $h _), + Or.inr (Polynomial.Splits.reverse $h), + Or.inr (Polynomial.Splits.of_reverse $h), + Or.inr (Polynomial.Splits.X_pow_mul_reverse $h _), Or.inr ((RealRooted.DegreeDropReversal.splits_X_pow_mul_iff _).mpr $h), Or.inr ((RealRooted.DegreeDropReversal.splits_X_pow_mul_iff _).mp $h), - RealRooted.pow_eq_zero_or_splits $h _, + Or.inr ((splits_of_eq_zero_or_splits $h).pow _), RealRooted.pow_eq_zero_or_splits_of_isRealRooted $h _, RealRooted.reverse_eq_zero_or_splits $h, RealRooted.eq_zero_or_splits_of_reverse $h, @@ -967,14 +975,16 @@ macro_rules right := $hq:term) => `(tactic| rr_first_exact - RealRooted.mul_eq_zero_or_splits $hp $hq, - RealRooted.mul_eq_zero_or_splits $hq $hp) + (Or.inr ((splits_of_eq_zero_or_splits $hp).mul + (splits_of_eq_zero_or_splits $hq))), + (Or.inr ((splits_of_eq_zero_or_splits $hq).mul + (splits_of_eq_zero_or_splits $hp)))) | `(tactic| rr_zero_or_splits_pow using zero_or_splits := $h:term, exponent := $n:term) => `(tactic| - exact RealRooted.pow_eq_zero_or_splits $h $n) + exact Or.inr ((splits_of_eq_zero_or_splits $h).pow $n)) | `(tactic| rr_zero_or_splits_reverse using zero_or_splits := $h:term) => @@ -1015,8 +1025,10 @@ macro_rules | rr_lookup | rr_zero_or_splits using rr_lookup_term | assumption - | (apply RealRooted.mul_eq_zero_or_splits <;> rr_zero_or_splits) - | (apply RealRooted.pow_eq_zero_or_splits <;> rr_zero_or_splits) + | (apply Or.inr; apply Polynomial.Splits.mul <;> + apply splits_of_eq_zero_or_splits; rr_zero_or_splits) + | (apply Or.inr; apply Polynomial.Splits.pow; + apply splits_of_eq_zero_or_splits; rr_zero_or_splits) -- `apply` rejects a non-disjunction before `rr_splits` runs; `exact Or.inr (by …)` -- would elaborate the `by` block first | (apply Or.inr; rr_splits; done) diff --git a/RealRooted/Tactic/SideGoals.lean b/RealRooted/Tactic/SideGoals.lean index 029783332..02ced046b 100644 --- a/RealRooted/Tactic/SideGoals.lean +++ b/RealRooted/Tactic/SideGoals.lean @@ -323,8 +323,8 @@ macro_rules rr_nonneg_coeffs_C_mul using scalar_nonneg := $ha:term, poly_nonneg := $hp:term) => `(tactic| first - | exact RealRooted.nonnegCoeffs_C_mul $ha $hp - | simpa only [mul_comm] using RealRooted.nonnegCoeffs_C_mul $ha $hp) + | exact RealRooted.hasNonnegCoeffs_C_mul $ha $hp + | simpa only [mul_comm] using RealRooted.hasNonnegCoeffs_C_mul $ha $hp) | `(tactic| rr_nonneg_coeffs_X_mul using poly_nonneg := $hp:term) => `(tactic| first @@ -374,7 +374,7 @@ macro_rules rr_close_side | apply RealRooted.HasNonnegCoeffs.derivative rr_nonneg_coeffs - | apply RealRooted.nonnegCoeffs_C_mul + | apply RealRooted.hasNonnegCoeffs_C_mul · rr_side_nonneg · rr_nonneg_coeffs | apply RealRooted.HasNonnegCoeffs.X_mul diff --git a/RealRooted/Tactic/SignAssembly.lean b/RealRooted/Tactic/SignAssembly.lean index 1016acfa2..893ee5b6d 100644 --- a/RealRooted/Tactic/SignAssembly.lean +++ b/RealRooted/Tactic/SignAssembly.lean @@ -105,7 +105,7 @@ private theorem isRealRooted_of_two_left_roots_of_strict_signs rw [← Multiset.coe_card] exact Multiset.card_le_card hroots_sub have hupper : F.roots.card ≤ F.natDegree := card_roots' F - refine ⟨hF_pos.ne_zero, splits_of_card_roots ?_⟩ + refine ⟨hF_pos.ne_zero, Polynomial.splits_iff_card_roots.mpr ?_⟩ lia /-- Strict sign changes on a nonempty sorted list, together with a positive @@ -169,7 +169,7 @@ theorem isRealRooted_of_strict_signs_of_natDegree_eq_add_two (ha_pos : 0 < F.eval a) : F ≠ 0 ∧ F.Splits := by have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] apply isRealRooted_of_strict_signs_of_natDegree_eq_length_add_two hF_pos hF_odd hrs_sorted (by lia) hn hsign hleft hright ha_lt ha_pos @@ -235,7 +235,7 @@ theorem isRealRooted_of_strict_signs_of_natDegree_eq_add_two_even (ha_neg : F.eval a < 0) : F ≠ 0 ∧ F.Splits := by have hrs_len : rs.length = f.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hf_splits] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hf_splits] apply isRealRooted_of_strict_signs_of_natDegree_eq_length_add_two_even hF_pos hF_even hrs_sorted (by lia) hn hsign hleft hright ha_lt ha_neg diff --git a/RealRooted/Tactic/WagnerX/Frontend.lean b/RealRooted/Tactic/WagnerX/Frontend.lean index ecaae4efd..7b562f9a2 100644 --- a/RealRooted/Tactic/WagnerX/Frontend.lean +++ b/RealRooted/Tactic/WagnerX/Frontend.lean @@ -28,17 +28,15 @@ macro_rules | `(tactic| rr_strict_interl_mul_X_both using proper := $hstrictInterl:term, - left_nonneg := $hfnn:term, - right_nonneg := $hgnn:term) => + left_nonneg := $_hfnn:term, + right_nonneg := $_hgnn:term) => `(tactic| - exact RealRooted.StrictInterl.mul_X_both_of_nonneg $hstrictInterl $hfnn $hgnn) + simpa using RealRooted.StrictInterl.mul_X_sub_C_both $hstrictInterl 0) | `(tactic| rr_strict_interl_mul_X_both) => `(tactic| exact (by - apply RealRooted.StrictInterl.mul_X_both_of_nonneg - case h => rr_lookup [rr_base_strict_interl] - case hfnn => rr_lookup [rr_nonneg] - case hgnn => rr_lookup [rr_nonneg])) + simpa using RealRooted.StrictInterl.mul_X_sub_C_both + (by rr_lookup [rr_base_strict_interl]) 0)) | `(tactic| rr_strict_interl_C_mul_X using proper := $hstrictInterl:term, diff --git a/RealRooted/Tactic/WagnerX/PositiveLag.lean b/RealRooted/Tactic/WagnerX/PositiveLag.lean index e46eff6f2..ca9b1988c 100644 --- a/RealRooted/Tactic/WagnerX/PositiveLag.lean +++ b/RealRooted/Tactic/WagnerX/PositiveLag.lean @@ -173,8 +173,8 @@ theorem natDegree_pos_X_lag_combo_sequence {P : Nat → ℝ[X]} exact hlt refine ⟨?_, ?_⟩ · rw [hrec m, - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff - hdlt hlag_pos, + Polynomial.natDegree_add_eq_right_of_natDegree_lt + hdlt, hlag_deg] lia · rw [hrec m] diff --git a/RealRooted/ThreeTermRecurrence/LagFeedback.lean b/RealRooted/ThreeTermRecurrence/LagFeedback.lean index 1f469d609..36cee6891 100644 --- a/RealRooted/ThreeTermRecurrence/LagFeedback.lean +++ b/RealRooted/ThreeTermRecurrence/LagFeedback.lean @@ -41,8 +41,8 @@ theorem strictInterl_of_lagFeedback {P : ℕ → ℝ[X]} {p : ℕ} {α : ℝ} {c have hNn : HasNonnegCoeffs (P n) := by simpa using hN 0 (by lia) have hlast : HasNonnegCoeffs (P (n + p)) := by rw [hrec n] - exact (nonnegCoeffs_C_mul hα.le (hN (p - 1) (by lia))).add - ((nonnegCoeffs_C_mul (hc n).le hasNonnegCoeffs_X).mul hNn) + exact (hasNonnegCoeffs_C_mul hα.le (hN (p - 1) (by lia))).add + ((hasNonnegCoeffs_C_mul (hc n).le hasNonnegCoeffs_X).mul hNn) -- the new pairs `P (n + 1 + i) ≺ P (n + p)` have hnew : ∀ i, i + 1 < p → StrictInterl (P (n + (i + 1))) (P (n + p)) := by intro i hi @@ -60,10 +60,10 @@ theorem strictInterl_of_lagFeedback {P : ℕ → ℝ[X]} {p : ℕ} {α : ℝ} {c have hg := h2.C_mul_right (hc n).ne' rw [hrec n, mul_assoc (C (c n))] exact hf.add_of_left hg - (hasPosLeadingCoeff_of_nonneg (nonnegCoeffs_C_mul hα.le (hN (p - 1) (by lia))) + (hasPosLeadingCoeff_of_nonneg (hasNonnegCoeffs_C_mul hα.le (hN (p - 1) (by lia))) hf.2.1.1) (hasPosLeadingCoeff_of_nonneg - ((nonnegCoeffs_C_mul (hc n).le (hasNonnegCoeffs_X.mul hNn))) hg.2.1.1) + ((hasNonnegCoeffs_C_mul (hc n).le (hasNonnegCoeffs_X.mul hNn))) hg.2.1.1) refine ⟨fun i j hij hj => ?_, fun i hi => ?_⟩ · rcases Nat.lt_or_ge (j + 1) p with h | h · rw [show n + 1 + i = n + (i + 1) by lia, show n + 1 + j = n + (j + 1) by lia] diff --git a/RealRooted/Transforms/BrandenE/WeightedSum.lean b/RealRooted/Transforms/BrandenE/WeightedSum.lean index ace8d11a0..4de17b470 100644 --- a/RealRooted/Transforms/BrandenE/WeightedSum.lean +++ b/RealRooted/Transforms/BrandenE/WeightedSum.lean @@ -64,7 +64,7 @@ theorem brandenBasisWeightedSum_nonneg rw [brandenBasisWeightedSum] apply hasNonnegCoeffs_finsetSum intro k hk - exact nonnegCoeffs_C_mul (ha k hk) (brandenBasisImage_nonneg n k) + exact hasNonnegCoeffs_C_mul (ha k hk) (brandenBasisImage_nonneg n k) /-- Strictly positive combinations of in-range basis images are nonzero and split over the reals in every ambient degree. -/ @@ -157,7 +157,7 @@ theorem brandenBasisWeightedSum_interl_of_le exact Interl.C_mul_right_of_nonneg (brandenBasisImage_zero_strictInterl n k (hkn k hk)).toInterl (ha k hk) · intro k hk - exact nonnegCoeffs_C_mul (ha k hk) (brandenBasisImage_nonneg n k) + exact hasNonnegCoeffs_C_mul (ha k hk) (brandenBasisImage_nonneg n k) /-- With at least one positive weight, the weak cone relation is strict. -/ theorem brandenBasisWeightedSum_strictInterl_of_le diff --git a/RealRooted/VeroneseMatrix.lean b/RealRooted/VeroneseMatrix.lean index 046177fdb..1eaa0b19a 100644 --- a/RealRooted/VeroneseMatrix.lean +++ b/RealRooted/VeroneseMatrix.lean @@ -535,7 +535,7 @@ theorem hasNonnegCoeffs_veroneseLinearFactorRowDesc_entry rw [hqeq] apply HasNonnegCoeffs.add · split - · exact nonnegCoeffs_C_mul ha hasNonnegCoeffs_one + · exact hasNonnegCoeffs_C_mul ha hasNonnegCoeffs_one · simpa using hasNonnegCoeffs_zero · split <;> split <;> simp_all [hasNonnegCoeffs_one, hasNonnegCoeffs_zero, hasNonnegCoeffs_X] @@ -742,7 +742,7 @@ lemma isInterlacingSeq0Nonneg_map_C_mul simpa [i', j'] using interl_C_mul_both hc hinterl · intro p hp rcases List.mem_map.1 hp with ⟨q, hq, rfl⟩ - exact nonnegCoeffs_C_mul hc_nonneg (hfs.2 q hq) + exact hasNonnegCoeffs_C_mul hc_nonneg (hfs.2 q hq) /-- General real-rooted nonnegative-coefficient case: the descending Veronese sections are weakly interlacing, and every nonzero section is real-rooted. -/ @@ -762,7 +762,7 @@ theorem isInterlacingSeq0Nonneg_and_real_veroneseSectionPolynomialListDesc_of_re C p.leadingCoeff * linearFactorProduct as = p := by rw [hprod] exact Polynomial.C_leadingCoeff_mul_prod_multiset_X_sub_C - (card_roots_of_splits hprr_splits) + (Polynomial.splits_iff_card_roots.mp hprr_splits) have hlead_pos : 0 < p.leadingCoeff := hpnn.pos_leadingCoeff hprr_ne have hpkg := isInterlacingSeq0Nonneg_and_real_veroneseSectionPolynomialListDesc_linearFactorProduct diff --git a/RealRooted/WagnerRightSum.lean b/RealRooted/WagnerRightSum.lean index d3c543e05..2aa25a4da 100644 --- a/RealRooted/WagnerRightSum.lean +++ b/RealRooted/WagnerRightSum.lean @@ -154,7 +154,7 @@ private lemma wagner1_roots_exist_of_no_common_right (f g : ℝ[X]) /-- If `bigger` has a root `p` below all roots of `smaller`, and `smaller + bigger` and `smaller + bigger` has degree one more than `smaller`, then `smaller + bigger` has a root ≤ p. Used for the mixed-degree cases in Wagner (1). -/ -lemma exists_root_le_of_mixed {smaller bigger : ℝ[X]} +private lemma exists_root_le_of_mixed {smaller bigger : ℝ[X]} (hsmaller_ne : smaller ≠ 0) (hsmaller_pos : HasPosLeadingCoeff smaller) (hsum_pos : HasPosLeadingCoeff (smaller + bigger)) @@ -215,9 +215,9 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} (by simp [hss_f_eq]) (by simp [hss_g_eq]) (by simp) (by simp) hno_rs_f have hf_deg : ss_f.length = f.natDegree := by - rw [← card_roots_of_splits hf.2, ← Multiset.coe_card, hss_f_eq] + rw [← Polynomial.splits_iff_card_roots.mp hf.2, ← Multiset.coe_card, hss_f_eq] have hg_deg : ss_g.length = g.natDegree := by - rw [← card_roots_of_splits hg.2, ← Multiset.coe_card, hss_g_eq] + rw [← Polynomial.splits_iff_card_roots.mp hg.2, ← Multiset.coe_card, hss_g_eq] have hdeg_eq : f.natDegree = g.natDegree := by lia have hfg_ne := add_ne_zero_of_same_natDegree_of_posLeadingCoeff hdeg_eq hf_pos hg_pos have hfg_deg := natDegree_add_eq_of_same_natDegree_of_posLeadingCoeff hdeg_eq hf_pos hg_pos @@ -233,7 +233,7 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} (f + g).roots.card ≤ (f + g).natDegree := card_roots' (f + g) _ = us.length := hfg_natDeg have hfg_rr : ((f + g) ≠ 0 ∧ (f + g).Splits) := by - refine ⟨hfg_ne, splits_of_card_roots ?_⟩ + refine ⟨hfg_ne, Polynomial.splits_iff_card_roots.mpr ?_⟩ rw [← hus_eq, Multiset.coe_card, hfg_natDeg] exact ⟨hfg_rr, hh, us, rs_f, pairwise_le_of_listInterlaces us rs_f hus_int, hrs_f_sorted, hus_eq, hrs_f_eq, @@ -254,18 +254,18 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} have hs₁_root : g.IsRoot s₁_g := (mem_roots hg.1).mp (by rw [← hss_g_eq]; simp) have hf_deg : ss_f.length = f.natDegree := by - have := card_roots_of_splits hf.2 + have := Polynomial.splits_iff_card_roots.mp hf.2 rw [← hss_f_eq, Multiset.coe_card] at this lia have hg_deg : g.natDegree = f.natDegree + 1 := by have : (s₁_g :: rest_g).length = g.natDegree := by - have := card_roots_of_splits hg.2 + have := Polynomial.splits_iff_card_roots.mp hg.2 rw [← hss_g_eq, Multiset.coe_card] at this lia lia have hdeg_lt : f.natDegree < g.natDegree := by lia have hfg_deg : (f + g).natDegree = g.natDegree := - natDegree_add_eq_right_of_natDegree_lt_of_posLeadingCoeff hdeg_lt hg_pos + Polynomial.natDegree_add_eq_right_of_natDegree_lt hdeg_lt have hfg_pos : HasPosLeadingCoeff (f + g) := hasPosLeadingCoeff_add_of_natDegree_lt_right hdeg_lt hg_pos have hsmaller_gt : ∀ t ∈ f.roots, s₁_g < t := by @@ -316,7 +316,7 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} _ = us.length + 1 := by lia _ = (u₀ :: us).length := by simp have hfg_rr : ((f + g) ≠ 0 ∧ (f + g).Splits) := by - refine ⟨hfg_ne, splits_of_card_roots ?_⟩ + refine ⟨hfg_ne, Polynomial.splits_iff_card_roots.mpr ?_⟩ rw [← hroots_eq, Multiset.coe_card] grind exact ⟨hfg_rr, hh, u₀ :: us, r₁ :: rest_rs, @@ -325,9 +325,9 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} ⟨le_trans hu₀_le hs₁_le, hus_int⟩⟩⟩ · rcases hcase_g with ⟨hlen_g, hint_g⟩ | ⟨hlen_g_alt, halt_g⟩ · have hf_deg : ss_f.length = f.natDegree := by - rw [← card_roots_of_splits hf.2, ← Multiset.coe_card, hss_f_eq] + rw [← Polynomial.splits_iff_card_roots.mp hf.2, ← Multiset.coe_card, hss_f_eq] have hg_deg : ss_g.length = g.natDegree := by - rw [← card_roots_of_splits hg.2, ← Multiset.coe_card, hss_g_eq] + rw [← Polynomial.splits_iff_card_roots.mp hg.2, ← Multiset.coe_card, hss_g_eq] have hrs_eq : rs_f = rs_g := by apply List.Perm.eq_of_pairwise' hrs_f_sorted hrs_g_sorted exact Multiset.coe_eq_coe.mp (hrs_f_eq.trans hrs_g_eq.symm) @@ -339,11 +339,11 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} rcases rs_f with _ | ⟨r₁, rest_rs⟩ · simp only [List.length_nil] at hlen_f_alt hlen_g_alt have hfnd : f.natDegree = 0 := by - have := card_roots_of_splits hf.2 + have := Polynomial.splits_iff_card_roots.mp hf.2 rw [← hss_f_eq, Multiset.coe_card] at this lia have hgnd : g.natDegree = 0 := by - have := card_roots_of_splits hg.2 + have := Polynomial.splits_iff_card_roots.mp hg.2 rw [← hss_g_eq, Multiset.coe_card] at this lia have hfgnd : (f + g).natDegree = 0 := by grind [natDegree_add_le f g] @@ -353,7 +353,8 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} ⟨hfg_ne, Polynomial.Splits.of_natDegree_eq_zero hfgnd⟩ refine ⟨hfg_rr, hh, [], [], List.Pairwise.nil, List.Pairwise.nil, ?_, hrs_f_eq, Or.inr ⟨rfl, trivial⟩⟩ - exact (Multiset.card_eq_zero.mp (by rw [card_roots_of_splits hfg_rr.2, hfgnd])).symm + exact (Multiset.card_eq_zero.mp (by + rw [Polynomial.splits_iff_card_roots.mp hfg_rr.2, hfgnd])).symm · obtain ⟨s₁_f, rest_f, rfl⟩ : ∃ a l, ss_f = a :: l := by cases ss_f with | nil => simp at hlen_f_alt @@ -369,11 +370,11 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} have hs₁g_root : g.IsRoot s₁_g := (mem_roots hg.1).mp (by rw [← hss_g_eq]; simp) have hf_deg : (s₁_f :: rest_f).length = f.natDegree := by - have := card_roots_of_splits hf.2 + have := Polynomial.splits_iff_card_roots.mp hf.2 rw [← hss_f_eq, Multiset.coe_card] at this lia have hg_deg : (s₁_g :: rest_g).length = g.natDegree := by - have := card_roots_of_splits hg.2 + have := Polynomial.splits_iff_card_roots.mp hg.2 rw [← hss_g_eq, Multiset.coe_card] at this lia have hdeg_eq : f.natDegree = g.natDegree := by lia @@ -444,7 +445,7 @@ theorem StrictInterl.add_of_right_of_no_common_right {f g h : ℝ[X]} _ = us.length + 1 := by lia _ = (c :: us).length := by simp have hfg_rr : ((f + g) ≠ 0 ∧ (f + g).Splits) := by - refine ⟨hfg_ne, splits_of_card_roots ?_⟩ + refine ⟨hfg_ne, Polynomial.splits_iff_card_roots.mpr ?_⟩ rw [← hroots_eq, Multiset.coe_card] grind exact ⟨hfg_rr, hh, c :: us, r₁ :: rest_rs, hpw.imp le_of_lt, diff --git a/RealRooted/WagnerRightSum/Sign.lean b/RealRooted/WagnerRightSum/Sign.lean index 1a264880b..ea99cb6b1 100644 --- a/RealRooted/WagnerRightSum/Sign.lean +++ b/RealRooted/WagnerRightSum/Sign.lean @@ -71,7 +71,7 @@ private lemma sign_of_prod_countP (s : Multiset ℝ) (f : ℝ → ℝ) (p : ℝ /-- If two multisets have the same count of "negative-producing" elements, then the product of their mapped products is non-negative. -/ -lemma prod_mul_prod_nonneg_of_same_neg_count {s₁ s₂ : Multiset ℝ} +private lemma prod_mul_prod_nonneg_of_same_neg_count {s₁ s₂ : Multiset ℝ} {f g : ℝ → ℝ} {p : ℝ → Prop} [DecidablePred p] (hf_pos : ∀ x ∈ s₁, ¬p x → 0 ≤ f x) (hf_neg : ∀ x ∈ s₁, p x → f x ≤ 0) @@ -233,19 +233,17 @@ This holds because: The count equality (3) follows from the interlacing giving one root per interval. -/ /-- Evaluation of a real-rooted polynomial via its factorization. -/ +@[deprecated Polynomial.Splits.eval_eq_prod_roots +typeChanged (since := "2026-10-21")] lemma eval_eq_leadingCoeff_mul_prod_sub {p : ℝ[X]} (hp_splits : p.Splits) (x : ℝ) : - p.eval x = p.leadingCoeff * (p.roots.map (x - ·)).prod := by - have hfact := C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hp_splits) - conv_lhs => rw [← hfact] - simp only [eval_C_mul, eval_multiset_prod, Multiset.map_map, Function.comp, - eval_sub, eval_X, eval_C] + p.eval x = p.leadingCoeff * (p.roots.map (x - ·)).prod := + hp_splits.eval_eq_prod_roots x lemma eval_pos_of_all_roots_lt {p : ℝ[X]} {r : ℝ} (hp_ne : p ≠ 0) (hp_splits : p.Splits) (hp_pos : HasPosLeadingCoeff p) (hlt : ∀ t ∈ p.roots, t < r) : 0 < p.eval r := by - rw [eval_eq_leadingCoeff_mul_prod_sub hp_splits r] + rw [Polynomial.Splits.eval_eq_prod_roots hp_splits r] exact mul_pos hp_pos (Multiset.prod_pos (by simp_all)) /-- If two polynomials both precede the same right-hand polynomial with positive @@ -265,7 +263,7 @@ lemma eval_mul_eval_nonneg_of_strictInterl_right {f g h : ℝ[X]} have hr_mem_rs : r ∈ rs_f := by apply Multiset.mem_coe.mp simp_all - rw [eval_eq_leadingCoeff_mul_prod_sub hf.2 r, eval_eq_leadingCoeff_mul_prod_sub hg.2 r] + rw [Polynomial.Splits.eval_eq_prod_roots hf.2 r, Polynomial.Splits.eval_eq_prod_roots hg.2 r] rw [← hss_f_eq, ← hss_g_eq] have hprod_f : ((↑ss_f : Multiset ℝ).map (r - ·)).prod = (ss_f.map (r - ·)).prod := rfl @@ -345,8 +343,8 @@ lemma opposite_sign_at_interlacing_roots {f g : ℝ[X]} (hg_dichotomy : ∀ r ∈ g.roots.erase t, r ≤ a ∨ b ≤ r) (hcount_eq : (g.roots.erase t).countP (b ≤ ·) = (f.roots.erase s).countP (b ≤ ·)) : g.eval s * f.eval t ≤ 0 := by - rw [eval_eq_leadingCoeff_mul_prod_sub hg_splits s, - eval_eq_leadingCoeff_mul_prod_sub hf_splits t] + rw [Polynomial.Splits.eval_eq_prod_roots hg_splits s, + Polynomial.Splits.eval_eq_prod_roots hf_splits t] have hlcg := hg_pos; have hlcf := hf_pos unfold HasPosLeadingCoeff at hlcg hlcf suffices h : (g.roots.map (s - ·)).prod * (f.roots.map (t - ·)).prod ≤ 0 by diff --git a/RealRooted/WagnerX/AffineFactors.lean b/RealRooted/WagnerX/AffineFactors.lean index 9270a0fa9..2d556460f 100644 --- a/RealRooted/WagnerX/AffineFactors.lean +++ b/RealRooted/WagnerX/AffineFactors.lean @@ -22,101 +22,6 @@ private lemma mul_X_sub_C_comp_X_add_C (p : ℝ[X]) (r : ℝ) : simp only [mul_comp, sub_comp, X_comp, C_comp] ring -private lemma coe_orderedInsert_eq_roots_mul_X_sub_C {p : ℝ[X]} (hp : p ≠ 0) - {ss : List ℝ} (hss : (↑ss : Multiset ℝ) = p.roots) (r : ℝ) : - (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * p).roots := by - have hinsert : - (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ({r} : Multiset ℝ) + ↑ss := by - calc - (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ↑(r :: ss) := - Multiset.coe_eq_coe.mpr (List.perm_orderedInsert (r := (· ≤ ·)) r ss) - _ = ({r} : Multiset ℝ) + ↑ss := by simp - have hroots : ({r} : Multiset ℝ) + ↑ss = ((X - C r) * p).roots := by - rw [hss] - simpa [roots_X_sub_C] using (roots_mul (mul_ne_zero (X_sub_C_ne_zero r) hp)).symm - exact hinsert.trans hroots - -/-- Multiplying both polynomials by the same affine factor preserves strict -interlacing when all original roots lie to its left. -/ -theorem StrictInterl.mul_X_sub_C_both_of_roots_le {f g : ℝ[X]} - (h : StrictInterl f g) (r : ℝ) - (hf_le : ∀ s ∈ f.roots, s ≤ r) - (hg_le : ∀ s ∈ g.roots, s ≤ r) : - StrictInterl ((X - C r) * f) ((X - C r) * g) := by - set f' := f.comp (X + C r) - set g' := g.comp (X + C r) - have hfg' : StrictInterl f' g' := by - simpa [f', g'] using (StrictInterl.comp_X_add_C_iff (f := f) (g := g) r).2 h - have hX' : StrictInterl (X * f') (X * g') := - hfg'.mul_X_both_of_roots_nonpos - (by simpa [f'] using roots_comp_X_add_C_nonpos_of_le hf_le) - (by simpa [g'] using roots_comp_X_add_C_nonpos_of_le hg_le) - exact - (StrictInterl.comp_X_add_C_iff (f := (X - C r) * f) (g := (X - C r) * g) r).1 - (by simpa [f', g', mul_X_sub_C_comp_X_add_C] using hX') - -/-- Multiplying both polynomials by the same affine factor preserves strict -interlacing. -/ -theorem StrictInterl.mul_X_sub_C_both {f g : ℝ[X]} (h : StrictInterl f g) (r : ℝ) : - StrictInterl ((X - C r) * f) ((X - C r) * g) := by - rcases h with ⟨hf, hg, ss, rs, hss, hrs, hss_eq, hrs_eq, hcase⟩ - refine ⟨isRealRooted_mul (isRealRooted_X_sub_C r).1 (isRealRooted_X_sub_C r).2 hf.1 hf.2, - isRealRooted_mul (isRealRooted_X_sub_C r).1 (isRealRooted_X_sub_C r).2 hg.1 hg.2, - ss.orderedInsert (· ≤ ·) r, rs.orderedInsert (· ≤ ·) r, - hss.orderedInsert _ _, hrs.orderedInsert _ _, ?_, ?_, ?_⟩ - · exact coe_orderedInsert_eq_roots_mul_X_sub_C hf.1 hss_eq r - · exact coe_orderedInsert_eq_roots_mul_X_sub_C hg.1 hrs_eq r - · rcases hcase with ⟨hlen, hint⟩ | ⟨hlen, halt⟩ - · refine Or.inl ⟨?_, listInterlaces_orderedInsert hlen hint r⟩ - rw [List.orderedInsert_length (r := (· ≤ ·)) ss r, - List.orderedInsert_length (r := (· ≤ ·)) rs r] - lia - · exact Or.inr ⟨by - rw [List.orderedInsert_length (r := (· ≤ ·)) ss r, - List.orderedInsert_length (r := (· ≤ ·)) rs r] - lia, - listAlternates_orderedInsert hlen halt r⟩ - -/-- Cancelling a common affine factor preserves strict interlacing. -/ -theorem StrictInterl.of_mul_X_sub_C_both {f g : ℝ[X]} {r : ℝ} - (h : StrictInterl ((X - C r) * f) ((X - C r) * g)) : - StrictInterl f g := by - rcases h with ⟨hXf, hXg, ss_mul, rs_mul, hss_mul, hrs_mul, hss_mul_eq, hrs_mul_eq, hcase⟩ - have hf0 : f ≠ 0 := right_ne_zero_of_mul hXf.1 - have hg0 : g ≠ 0 := right_ne_zero_of_mul hXg.1 - have hf : (f ≠ 0 ∧ f.Splits) := isRealRooted_of_dvd hXf.1 hXf.2 hf0 (dvd_mul_left f _) - have hg : (g ≠ 0 ∧ g.Splits) := isRealRooted_of_dvd hXg.1 hXg.2 hg0 (dvd_mul_left g _) - set ss := f.roots.sort (· ≤ ·) - set rs := g.roots.sort (· ≤ ·) - have hss_eq : (↑ss : Multiset ℝ) = f.roots := Multiset.sort_eq .. - have hrs_eq : (↑rs : Multiset ℝ) = g.roots := Multiset.sort_eq .. - have hss_sorted : ss.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. - have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. - have hss_insert_eq : - (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * f).roots := - coe_orderedInsert_eq_roots_mul_X_sub_C hf.1 hss_eq r - have hrs_insert_eq : - (↑(rs.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * g).roots := - coe_orderedInsert_eq_roots_mul_X_sub_C hg.1 hrs_eq r - have hss_mul_is : ss_mul = ss.orderedInsert (· ≤ ·) r := - List.Perm.eq_of_pairwise' hss_mul (hss_sorted.orderedInsert _ _) - (Multiset.coe_eq_coe.mp (hss_mul_eq.trans hss_insert_eq.symm)) - have hrs_mul_is : rs_mul = rs.orderedInsert (· ≤ ·) r := - List.Perm.eq_of_pairwise' hrs_mul (hrs_sorted.orderedInsert _ _) - (Multiset.coe_eq_coe.mp (hrs_mul_eq.trans hrs_insert_eq.symm)) - refine ⟨hf, hg, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, ?_⟩ - rcases hcase with ⟨hlen, hint⟩ | ⟨hlen, halt⟩ - · rw [hss_mul_is, hrs_mul_is] at hint hlen - have hlen' : ss.length + 1 = rs.length := by - simp only [List.orderedInsert_length] at hlen - lia - exact Or.inl ⟨hlen', listInterlaces_of_orderedInsert r hlen' hss_sorted hrs_sorted hint⟩ - · rw [hss_mul_is, hrs_mul_is] at halt hlen - have hlen' : ss.length = rs.length := by - simp only [List.orderedInsert_length] at hlen - lia - exact Or.inr ⟨hlen', listAlternates_of_orderedInsert r hlen' hss_sorted hrs_sorted halt⟩ - /-- Multiplication by a common nonzero real-rooted factor preserves strict interlacing. -/ theorem StrictInterl.mul_common_factor {d f g : ℝ[X]} (h : StrictInterl f g) @@ -137,8 +42,8 @@ theorem StrictInterl.mul_common_factor {d f g : ℝ[X]} (h : StrictInterl f g) have hleft := StrictInterl.C_mul_left hprod hlc0 have hboth := StrictInterl.C_mul_right hleft hlc0 simpa [mul_assoc, mul_left_comm, mul_comm] using hboth - simpa [C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hd_splits), mul_assoc] - using hscaled + simpa [C_leadingCoeff_mul_prod_multiset_X_sub_C + (Polynomial.splits_iff_card_roots.mp hd_splits), mul_assoc] using hscaled theorem strictInterl_iff_strictInterl_mul_X_sub_C_of_roots_le {f g : ℝ[X]} (r : ℝ) (hf : f.Splits) (hg : g.Splits) diff --git a/RealRooted/WagnerX/ListInterlacing.lean b/RealRooted/WagnerX/ListInterlacing.lean index 152922e38..47fd2d97e 100644 --- a/RealRooted/WagnerX/ListInterlacing.lean +++ b/RealRooted/WagnerX/ListInterlacing.lean @@ -21,21 +21,6 @@ namespace RealRooted /-! ## List-level lemmas for interlacing -/ /-- Every element of `ss` is `≥` the first element of `rs` in a ListInterlaces. -/ -lemma listInterlaces_all_ge : - ∀ (ss rs : List ℝ) (r : ℝ), - ListInterlaces ss (r :: rs) → - ∀ s ∈ ss, r ≤ s - | [], _, _, _ => by simp - | [s], [], r, hint => by simp [ListInterlaces] at hint - | s :: ss', r₁ :: rs', r, hint => by - obtain ⟨hr, hsr₁, htail⟩ := hint - intro s' hs' - rcases List.mem_cons.mp hs' with rfl | hs'' - · lia - · exact le_trans (le_trans hr hsr₁) (listInterlaces_all_ge ss' rs' r₁ htail s' hs'') - | _ :: _ :: _, [], _, hint => by simp [ListInterlaces] at hint - -/-- All elements of `rs` in a `ListInterlaces ss (r :: rs)` are `≥ r`. -/ lemma listInterlaces_rs_all_ge : ∀ (ss rs : List ℝ) (r : ℝ), ListInterlaces ss (r :: rs) → @@ -52,7 +37,7 @@ lemma listInterlaces_rs_all_ge : /-- The tail factors in a differ-by-one interlacing layout are all nonnegative when paired against two ordered right-hand points. -/ -lemma listInterlaces_tail_pair_prod_nonneg : +private lemma listInterlaces_tail_pair_prod_nonneg : ∀ {ss : List ℝ} {r₁ r₂ : ℝ} {rest : List ℝ}, r₁ ≤ r₂ → ListInterlaces ss (r₂ :: rest) → @@ -86,18 +71,6 @@ lemma listInterlaces_prod_mul_prod_nonpos_at_heads _ ≤ 0 := mul_nonpos_of_nonpos_of_nonneg hs_head_nonpos htail_nonneg' /-- A list satisfying `ListInterlaces ss rs` is sorted (pairwise ≤). -/ -lemma pairwise_le_of_listInterlaces : - ∀ (ss rs : List ℝ), ListInterlaces ss rs → ss.Pairwise (· ≤ ·) - | [], _, _ => List.Pairwise.nil - | [_], _, _ => List.pairwise_singleton _ _ - | s₁ :: s₂ :: ss', r₁ :: r₂ :: rs', h => by - obtain ⟨_, hs₁r₂, htail⟩ := h - refine List.pairwise_cons.mpr ⟨?_, pairwise_le_of_listInterlaces _ _ htail⟩ - intro s hs - exact le_trans hs₁r₂ (listInterlaces_all_ge (s₂ :: ss') rs' r₂ htail s hs) - | _ :: _ :: _, [], h => by simp [ListInterlaces] at h - | _ :: _ :: _, [_], h => by simp [ListInterlaces] at h - lemma orderedInsert_eq_cons_of_forall_le {a : ℝ} : ∀ {l : List ℝ}, (∀ b ∈ l, a ≤ b) → l.orderedInsert (· ≤ ·) a = a :: l | [], _ => by simp @@ -307,7 +280,7 @@ lemma listInterlaces_of_listAlternates_append_zero : exact listInterlaces_of_listAlternates_append_zero (s' :: ss'') (r₂ :: rs'') (by simp_all) (by simp only [ListAlternates, List.cons_append]; lia) -lemma listInterlaces_of_listAlternates_append_right +private lemma listInterlaces_of_listAlternates_append_right {ss qs : List ℝ} {uR : ℝ} (hlen : qs.length + 1 = ss.length) (halt : ListAlternates ss (qs ++ [uR])) : @@ -334,7 +307,7 @@ lemma interlaces_of_strictInterl_sameDegree_rightmost_factor obtain ⟨ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, halt⟩ := hfg.exists_listAlternates_of_natDegree_eq hdeg have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hfg.1.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hfg.1.2] have hq_ne : q ≠ 0 := right_ne_zero_of_mul (by rw [← hgq]; exact hfg.2.1.1) have hq : q ≠ 0 ∧ q.Splits := by apply isRealRooted_of_dvd hfg.2.1.1 hfg.2.1.2 hq_ne @@ -347,7 +320,7 @@ lemma interlaces_of_strictInterl_sameDegree_rightmost_factor have hqs_eq : (↑qs : Multiset ℝ) = q.roots := Multiset.sort_eq .. have hqs_sorted : qs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. have hqs_len : qs.length = q.natDegree := by - simp [qs, card_roots_of_splits hq.2] + simp [qs, Polynomial.splits_iff_card_roots.mp hq.2] have hqs_le_uR : ∀ r ∈ qs, r ≤ uR := fun r hr => hright r (by rw [hgq, roots_mul (mul_ne_zero (X_sub_C_ne_zero uR) hq_ne), roots_X_sub_C] @@ -437,4 +410,84 @@ lemma listAlternates_of_append_zero_both : | [], _ :: _, hlen, _ => by simp at hlen | _ :: _, [], hlen, _ => by simp at hlen +private lemma coe_orderedInsert_eq_roots_mul_X_sub_C {p : ℝ[X]} (hp : p ≠ 0) + {ss : List ℝ} (hss : (↑ss : Multiset ℝ) = p.roots) (r : ℝ) : + (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * p).roots := by + have hinsert : + (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ({r} : Multiset ℝ) + ↑ss := by + calc + (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ↑(r :: ss) := + Multiset.coe_eq_coe.mpr (List.perm_orderedInsert (r := (· ≤ ·)) r ss) + _ = ({r} : Multiset ℝ) + ↑ss := by simp + have hroots : ({r} : Multiset ℝ) + ↑ss = ((X - C r) * p).roots := by + rw [hss] + simpa [roots_X_sub_C] using + (roots_mul (mul_ne_zero (X_sub_C_ne_zero r) hp)).symm + exact hinsert.trans hroots + +/-- Multiplying both polynomials by the same affine factor preserves strict +interlacing. -/ +theorem StrictInterl.mul_X_sub_C_both {f g : ℝ[X]} (h : StrictInterl f g) (r : ℝ) : + StrictInterl ((X - C r) * f) ((X - C r) * g) := by + rcases h with ⟨hf, hg, ss, rs, hss, hrs, hss_eq, hrs_eq, hcase⟩ + refine ⟨isRealRooted_mul (isRealRooted_X_sub_C r).1 (isRealRooted_X_sub_C r).2 hf.1 hf.2, + isRealRooted_mul (isRealRooted_X_sub_C r).1 (isRealRooted_X_sub_C r).2 hg.1 hg.2, + ss.orderedInsert (· ≤ ·) r, rs.orderedInsert (· ≤ ·) r, + hss.orderedInsert _ _, hrs.orderedInsert _ _, ?_, ?_, ?_⟩ + · exact coe_orderedInsert_eq_roots_mul_X_sub_C hf.1 hss_eq r + · exact coe_orderedInsert_eq_roots_mul_X_sub_C hg.1 hrs_eq r + · rcases hcase with ⟨hlen, hint⟩ | ⟨hlen, halt⟩ + · refine Or.inl ⟨?_, listInterlaces_orderedInsert hlen hint r⟩ + rw [List.orderedInsert_length (r := (· ≤ ·)) ss r, + List.orderedInsert_length (r := (· ≤ ·)) rs r] + lia + · exact Or.inr ⟨by + rw [List.orderedInsert_length (r := (· ≤ ·)) ss r, + List.orderedInsert_length (r := (· ≤ ·)) rs r] + lia, + listAlternates_orderedInsert hlen halt r⟩ + +/-- Cancelling a common affine factor preserves strict interlacing. -/ +theorem StrictInterl.of_mul_X_sub_C_both {f g : ℝ[X]} {r : ℝ} + (h : StrictInterl ((X - C r) * f) ((X - C r) * g)) : + StrictInterl f g := by + rcases h with + ⟨hXf, hXg, ss_mul, rs_mul, hss_mul, hrs_mul, hss_mul_eq, hrs_mul_eq, hcase⟩ + have hf0 : f ≠ 0 := right_ne_zero_of_mul hXf.1 + have hg0 : g ≠ 0 := right_ne_zero_of_mul hXg.1 + have hf : f ≠ 0 ∧ f.Splits := + ⟨hf0, hXf.2.of_dvd hXf.1 (dvd_mul_left f _)⟩ + have hg : g ≠ 0 ∧ g.Splits := + ⟨hg0, hXg.2.of_dvd hXg.1 (dvd_mul_left g _)⟩ + set ss := f.roots.sort (· ≤ ·) + set rs := g.roots.sort (· ≤ ·) + have hss_eq : (↑ss : Multiset ℝ) = f.roots := Multiset.sort_eq .. + have hrs_eq : (↑rs : Multiset ℝ) = g.roots := Multiset.sort_eq .. + have hss_sorted : ss.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. + have hrs_sorted : rs.Pairwise (· ≤ ·) := Multiset.pairwise_sort .. + have hss_insert_eq : + (↑(ss.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * f).roots := + coe_orderedInsert_eq_roots_mul_X_sub_C hf.1 hss_eq r + have hrs_insert_eq : + (↑(rs.orderedInsert (· ≤ ·) r) : Multiset ℝ) = ((X - C r) * g).roots := + coe_orderedInsert_eq_roots_mul_X_sub_C hg.1 hrs_eq r + have hss_mul_is : ss_mul = ss.orderedInsert (· ≤ ·) r := + List.Perm.eq_of_pairwise' hss_mul (hss_sorted.orderedInsert _ _) + (Multiset.coe_eq_coe.mp (hss_mul_eq.trans hss_insert_eq.symm)) + have hrs_mul_is : rs_mul = rs.orderedInsert (· ≤ ·) r := + List.Perm.eq_of_pairwise' hrs_mul (hrs_sorted.orderedInsert _ _) + (Multiset.coe_eq_coe.mp (hrs_mul_eq.trans hrs_insert_eq.symm)) + refine ⟨hf, hg, ss, rs, hss_sorted, hrs_sorted, hss_eq, hrs_eq, ?_⟩ + rcases hcase with ⟨hlen, hint⟩ | ⟨hlen, halt⟩ + · rw [hss_mul_is, hrs_mul_is] at hint hlen + have hlen' : ss.length + 1 = rs.length := by + simp only [List.orderedInsert_length] at hlen + lia + exact Or.inl ⟨hlen', listInterlaces_of_orderedInsert r hlen' hss_sorted hrs_sorted hint⟩ + · rw [hss_mul_is, hrs_mul_is] at halt hlen + have hlen' : ss.length = rs.length := by + simp only [List.orderedInsert_length] at hlen + lia + exact Or.inr ⟨hlen', listAlternates_of_orderedInsert r hlen' hss_sorted hrs_sorted halt⟩ + end RealRooted diff --git a/RealRooted/WagnerX/NonnegativeRoots.lean b/RealRooted/WagnerX/NonnegativeRoots.lean index a92827614..2f583a95c 100644 --- a/RealRooted/WagnerX/NonnegativeRoots.lean +++ b/RealRooted/WagnerX/NonnegativeRoots.lean @@ -53,7 +53,7 @@ lemma hasNonnegCoeffs_iff_pos_leadingCoeff_and_roots_nonpos {p : ℝ[X]} (hp : p exact ⟨hnn.pos_leadingCoeff hp₀, roots_nonpos_of_hasNonnegCoeffs hnn⟩ · rintro ⟨hp₀, hroots_nonpos⟩ refine ⟨?_, hp₀.ne_zero⟩ - rw [← C_leadingCoeff_mul_prod_multiset_X_sub_C (card_roots_of_splits hp)] + rw [← C_leadingCoeff_mul_prod_multiset_X_sub_C (Polynomial.splits_iff_card_roots.mp hp)] exact (hasNonnegCoeffs_C hp₀.le).mul (hasNonnegCoeffs_multiset_prod_X_sub_C p.roots hroots_nonpos) @@ -83,7 +83,7 @@ lemma hasNonnegCoeffs_of_dvd_of_hasPosLeadingCoeff refine ⟨hq_pos, ?_⟩ intro r hr have hrq : q.IsRoot r := (mem_roots hq_ne).mp hr - have hrp : p.IsRoot r := IsRoot.of_dvd hqp hrq + have hrp : p.IsRoot r := hrq.dvd hqp exact roots_nonpos_of_hasNonnegCoeffs hpnn r ((mem_roots hp_ne).mpr hrp) private lemma coe_append_zero_eq_roots_X_mul {f : ℝ[X]} (hf : f ≠ 0) @@ -109,8 +109,8 @@ theorem strictInterl_of_strictInterl_mul_X_of_sameDegree_of_roots_nonpos {f g : exact List.Perm.eq_of_pairwise' hrs_Xf hrs_f0 <| Multiset.coe_eq_coe.mp <| hrs_Xf_eq.trans (coe_append_zero_eq_roots_X_mul hf.1 hrs_f_eq).symm have hlen_fg : rs_f.length = ss_g.length := by - rw [← Multiset.coe_card, hrs_f_eq, card_roots_of_splits hf.2, - ← Multiset.coe_card, hss_g_eq, card_roots_of_splits hg.2, hdeg] + rw [← Multiset.coe_card, hrs_f_eq, Polynomial.splits_iff_card_roots.mp hf.2, + ← Multiset.coe_card, hss_g_eq, Polynomial.splits_iff_card_roots.mp hg.2, hdeg] rcases hshape with ⟨hlen, hint⟩ | ⟨hlen, _⟩ · rw [hrs_Xf_is] at hint hlen have hlen' : ss_g.length + 1 = (rs_f ++ [(0 : ℝ)]).length := by lia @@ -148,17 +148,17 @@ private theorem strictInterl_iff_mul_X_of_roots_nonpos_of_succ {f g : ℝ[X]} hrs_eq, hss0_eq, Or.inr ⟨by simp_all, listAlternates_append_zero ss rs hlen hint hrs_nonpos⟩⟩ · have : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf] have : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg] lia · -- Backward: StrictInterl g (X * f) → StrictInterl f g intro ⟨_, _, ss_g, rs_xf, hss_g, hrs_xf, hss_g_eq, hrs_xf_eq, hcase⟩ rcases hcase with ⟨hlen, _⟩ | ⟨hlen, halt⟩ · have : ss_g.length = g.natDegree := by - rw [← Multiset.coe_card, hss_g_eq, card_roots_of_splits hg] + rw [← Multiset.coe_card, hss_g_eq, Polynomial.splits_iff_card_roots.mp hg] have : rs_xf.length = (X * f).natDegree := by - rw [← Multiset.coe_card, hrs_xf_eq, card_roots_of_splits (by simp_all)] + rw [← Multiset.coe_card, hrs_xf_eq, Polynomial.splits_iff_card_roots.mp (by simp_all)] lia · set ss_f := f.roots.sort (· ≤ ·) have hss_f_eq : (↑ss_f : Multiset ℝ) = f.roots := Multiset.sort_eq .. @@ -193,9 +193,9 @@ theorem strictInterl_sameDegree_to_strictInterl_mul_X_of_roots_nonpos {f g : ℝ coe_append_zero_eq_roots_X_mul hf.1 hss_eq rcases hcase with ⟨hlen, hint⟩ | ⟨hlen, halt⟩ · have hss_len : ss.length = f.natDegree := by - rw [← Multiset.coe_card, hss_eq, card_roots_of_splits hf.2] + rw [← Multiset.coe_card, hss_eq, Polynomial.splits_iff_card_roots.mp hf.2] have hrs_len : rs.length = g.natDegree := by - rw [← Multiset.coe_card, hrs_eq, card_roots_of_splits hg.2] + rw [← Multiset.coe_card, hrs_eq, Polynomial.splits_iff_card_roots.mp hg.2] lia · refine ⟨hg, hXf_rr, rs, ss ++ [0], hrs, hss0_sorted, hrs_eq, hss0_eq, Or.inl ?_⟩ refine ⟨?_, listInterlaces_right_of_listAlternates_append_zero ss rs ?_ halt ?_⟩ @@ -284,34 +284,25 @@ theorem interl_mul_X_of_interl {f g : ℝ[X]} · exact interl_zero_left (X * f) · exact (strictInterl_mul_X_of_strictInterl_of_nonneg hfg hfnn hgnn).toInterl -private lemma roots_X_mul_nonpos {f : ℝ[X]} (hf : f ≠ 0) - (h : ∀ r ∈ f.roots, r ≤ 0) : ∀ r ∈ (X * f).roots, r ≤ 0 := by - intro r hr - rw [roots_mul (mul_ne_zero X_ne_zero hf), roots_X] at hr - rcases Multiset.mem_add.mp hr with hr | hr - · exact (Multiset.mem_singleton.mp hr).le - · exact h r hr - /-- Multiplying both polynomials by `X` preserves strict interlacing when all roots are nonpositive. -/ +@[deprecated StrictInterl.mul_X_sub_C_both +typeChanged (since := "2026-10-21")] theorem StrictInterl.mul_X_both_of_roots_nonpos {f g : ℝ[X]} (h : StrictInterl f g) - (hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) - (hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : - StrictInterl (X * f) (X * g) := - (strictInterl_iff_mul_X_of_roots_nonpos hg_nonpos - (roots_X_mul_nonpos h.1.1 hf_nonpos)).mp - ((strictInterl_iff_mul_X_of_roots_nonpos hf_nonpos hg_nonpos).mp h) + (_hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) + (_hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : + StrictInterl (X * f) (X * g) := by + simpa using h.mul_X_sub_C_both 0 /-- Cancelling a common factor `X` preserves strict interlacing when all remaining roots are nonpositive. -/ +@[deprecated StrictInterl.of_mul_X_sub_C_both +typeChanged (since := "2026-10-21")] theorem StrictInterl.of_mul_X_both_of_roots_nonpos {f g : ℝ[X]} (h : StrictInterl (X * f) (X * g)) - (hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) - (hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : - StrictInterl f g := - (strictInterl_iff_mul_X_of_roots_nonpos hf_nonpos hg_nonpos).mpr - ((strictInterl_iff_mul_X_of_roots_nonpos hg_nonpos - (roots_X_mul_nonpos (right_ne_zero_of_mul h.1.1) hf_nonpos)).mpr h) + (_hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) + (_hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : + StrictInterl f g := by + apply StrictInterl.of_mul_X_sub_C_both (r := 0) + simpa using h /-! ## Wagner `X`-multiplication interlacing bridges -/ @@ -334,21 +325,23 @@ lemma strictInterl_of_strictInterl_X_mul_of_nonneg {f g : ℝ[X]} (roots_nonpos_of_hasNonnegCoeffs hgnn)).mpr h /-- Nonnegative-coefficient form of the common-factor Wagner `X` bridge. -/ +@[deprecated StrictInterl.mul_X_sub_C_both +typeChanged (since := "2026-10-21")] theorem StrictInterl.mul_X_both_of_nonneg {f g : ℝ[X]} - (h : StrictInterl f g) (hfnn : HasNonnegCoeffs f) (hgnn : HasNonnegCoeffs g) : - StrictInterl (X * f) (X * g) := - h.mul_X_both_of_roots_nonpos - (roots_nonpos_of_hasNonnegCoeffs hfnn) - (roots_nonpos_of_hasNonnegCoeffs hgnn) + (h : StrictInterl f g) (_hfnn : HasNonnegCoeffs f) (_hgnn : HasNonnegCoeffs g) : + StrictInterl (X * f) (X * g) := by + simpa using h.mul_X_sub_C_both 0 /-- Multiplication by `X` on both sides is an equivalence on strict interlacing when all roots are nonpositive. -/ +@[deprecated StrictInterl.mul_X_sub_C_both +typeChanged (since := "2026-10-21")] theorem StrictInterl.mul_X_both_iff_of_roots_nonpos {f g : ℝ[X]} - (hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) - (hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : + (_hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) + (_hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : StrictInterl f g ↔ StrictInterl (X * f) (X * g) := - ⟨fun h => h.mul_X_both_of_roots_nonpos hf_nonpos hg_nonpos, - fun h => h.of_mul_X_both_of_roots_nonpos hf_nonpos hg_nonpos⟩ + ⟨fun h => by simpa using h.mul_X_sub_C_both 0, + fun h => by + apply StrictInterl.of_mul_X_sub_C_both (r := 0) + simpa using h⟩ /-- Multiplying both polynomials by `X` preserves zero-aware interlacing for polynomials with nonnegative coefficients. -/ @@ -358,13 +351,13 @@ theorem Interl.mul_X_both_of_nonneg {f g : ℝ[X]} rcases h with rfl | rfl | hfg · simpa using interl_zero_left (X * g) · simpa using interl_zero_right (X * f) - · exact (hfg.mul_X_both_of_nonneg hfnn hgnn).toInterl + · exact (by simpa using hfg.mul_X_sub_C_both 0 : StrictInterl (X * f) (X * g)).toInterl /-- Cancelling a common factor `X` preserves zero-aware interlacing for polynomials with nonnegative coefficients. -/ theorem Interl.of_mul_X_both_of_nonneg {f g : ℝ[X]} - (h : Interl (X * f) (X * g)) (hfnn : HasNonnegCoeffs f) - (hgnn : HasNonnegCoeffs g) : + (h : Interl (X * f) (X * g)) (_hfnn : HasNonnegCoeffs f) + (_hgnn : HasNonnegCoeffs g) : Interl f g := by by_cases hf0 : f = 0 · simpa [hf0] using interl_zero_left g @@ -372,9 +365,8 @@ theorem Interl.of_mul_X_both_of_nonneg {f g : ℝ[X]} · simpa [hg0] using interl_zero_right f have hstrict : StrictInterl (X * f) (X * g) := h.toStrictInterl_of_ne (mul_ne_zero X_ne_zero hf0) (mul_ne_zero X_ne_zero hg0) - exact - (hstrict.of_mul_X_both_of_roots_nonpos - (roots_nonpos_of_hasNonnegCoeffs hfnn) - (roots_nonpos_of_hasNonnegCoeffs hgnn)).toInterl + apply StrictInterl.toInterl + apply StrictInterl.of_mul_X_sub_C_both (r := 0) + simpa using hstrict end RealRooted diff --git a/RealRooted/WagnerX/ProperPosition.lean b/RealRooted/WagnerX/ProperPosition.lean index d36d12048..d50e80c47 100644 --- a/RealRooted/WagnerX/ProperPosition.lean +++ b/RealRooted/WagnerX/ProperPosition.lean @@ -15,12 +15,10 @@ namespace RealRooted /-- The derivative of a split nonnegative-coefficient polynomial preserves the Wagner `X`-multiplication interlacing relation. -/ theorem strictInterl_X_derivative_X_self_of_splits_nonneg {f : ℝ[X]} - (hf : f.Splits) (hdeg : 2 ≤ f.natDegree) (hfnn : HasNonnegCoeffs f) : + (hf : f.Splits) (hdeg : 2 ≤ f.natDegree) (_hfnn : HasNonnegCoeffs f) : StrictInterl (X * f.derivative) (X * f) := by have hder : StrictInterl f.derivative f := (derivative_interlaces_of_natDegree_ne_zero hf (by lia)).toStrictInterl - exact hder.mul_X_both_of_roots_nonpos - (roots_nonpos_of_hasNonnegCoeffs hfnn.derivative) - (roots_nonpos_of_hasNonnegCoeffs hfnn) + simpa using hder.mul_X_sub_C_both 0 end RealRooted diff --git a/RealRooted/WeightedSum.lean b/RealRooted/WeightedSum.lean index 2751b4018..bb0d816b5 100644 --- a/RealRooted/WeightedSum.lean +++ b/RealRooted/WeightedSum.lean @@ -51,7 +51,7 @@ theorem hasNonnegCoeffs_weightedSum (l : List (ℝ × ℝ[X])) apply hasNonnegCoeffs_sum intro p hp rcases List.mem_map.mp hp with ⟨ap, hap, rfl⟩ - exact nonnegCoeffs_C_mul (hweights ap hap) (hpolys ap hap) + exact hasNonnegCoeffs_C_mul (hweights ap hap) (hpolys ap hap) /-- Finite-function form of `weightedSum_eq_sum_map`. -/ theorem weightedSum_ofFn {n : ℕ} (w : Fin n → ℝ × ℝ[X]) : diff --git a/RealRooted/Wronskian/Algebra.lean b/RealRooted/Wronskian/Algebra.lean index 76747d783..c6f38c123 100644 --- a/RealRooted/Wronskian/Algebra.lean +++ b/RealRooted/Wronskian/Algebra.lean @@ -106,9 +106,7 @@ theorem iterated_laguerre_form_nonneg {p : ℝ[X]} (hp : p.Splits) (k : ℕ) 0 ≤ (derivative ((derivative^[k]) p)).eval t ^ 2 - ((derivative^[k]) p).eval t * (derivative (derivative ((derivative^[k]) p))).eval t := by - rcases iterate_derivative_eq_zero_or_splits hp k with h | h - · simp [h] - · exact laguerre_form_nonneg h t + exact laguerre_form_nonneg (hp.iterate_derivative k) t /-! ### The shifted Euler operator `θ⁺ = 1 + X·d/dX` -/ @@ -181,9 +179,7 @@ theorem laguerre_form_derivative_nonneg {p : ℝ[X]} (hp : p.Splits) (t : ℝ) : 0 ≤ (derivative (derivative p)).eval t ^ 2 - (derivative p).eval t * (derivative (derivative (derivative p))).eval t := by - rcases eq_zero_or_splits_derivative (Or.inr hp) with h0 | hs - · simp [h0] - · exact laguerre_form_nonneg hs t + exact laguerre_form_nonneg hp.derivative t /-! ### Wronskians of consecutive derivatives -/ diff --git a/RealRooted/Wronskian/Forward.lean b/RealRooted/Wronskian/Forward.lean index 8104556fc..0ed97042d 100644 --- a/RealRooted/Wronskian/Forward.lean +++ b/RealRooted/Wronskian/Forward.lean @@ -114,10 +114,10 @@ theorem wronskian_pos_of_strictInterl_succ {p q : ℝ[X]} have hp_deg : p.natDegree = n + 1 := hp_deg_succ have hss_len : ss.length = n := by have h1 : (↑ss : Multiset ℝ).card = q.roots.card := congrArg Multiset.card hss_coe - rwa [Multiset.coe_card, card_roots_of_splits hq_splits] at h1 + rwa [Multiset.coe_card, Polynomial.splits_iff_card_roots.mp hq_splits] at h1 have hrs_len : rs.length = n + 1 := by have h1 : (↑rs : Multiset ℝ).card = p.roots.card := congrArg Multiset.card hrs_coe - rwa [Multiset.coe_card, card_roots_of_splits hp_splits, hp_deg] at h1 + rwa [Multiset.coe_card, Polynomial.splits_iff_card_roots.mp hp_splits, hp_deg] at h1 have hinter : ListInterlaces ss rs := by rcases hbranch with ⟨_, h⟩ | ⟨hl, _⟩ · exact h diff --git a/RealRooted/Wronskian/Successor/Splits.lean b/RealRooted/Wronskian/Successor/Splits.lean index 7f2c1a944..c900029c9 100644 --- a/RealRooted/Wronskian/Successor/Splits.lean +++ b/RealRooted/Wronskian/Successor/Splits.lean @@ -135,6 +135,6 @@ theorem splits_of_wronskian_neg_succ {n : ℕ} refine le_antisymm (card_roots' g) ?_ rw [hg_deg] exact le_trans hcard (Multiset.toFinset_card_le _) - exact splits_of_card_roots hcard_roots + exact Polynomial.splits_iff_card_roots.mpr hcard_roots end RealRooted From 73a4b8bdb32a2ffaceacdae1b6dafa57e5216c73 Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 16:55:23 +0000 Subject: [PATCH 2/6] Drop unneeded nonnegativity hypotheses from common-factor interlacing - Add hypothesis-free `StrictInterl.mul_X_sub_C_both_iff`, `Interl.mul_X_sub_C_both`, `Interl.of_mul_X_sub_C_both`, `Interl.mul_X_both`, `Interl.of_mul_X_both`, `Interl.theta`, `Interl.thetaPlusOne` and `Interl.iterateThetaPlusOne`. - Rename `strictInterl_X_derivative_X_self_of_splits_nonneg` to `strictInterl_X_derivative_X_self_of_splits`. - Old names used downstream stay as dated deprecations; unused ones are removed. - Tactics get certificate-minimal syntax; the old forms still parse. - Fix the product branch of `rr_zero_or_splits`. Co-Authored-By: Claude Opus 5.5 --- PROOF_STATUS.md | 2 +- RealRooted/AffineProperPosition.lean | 9 +- RealRooted/Applications/OEIS/A304330.lean | 18 +--- .../Applications/OEIS/TouchardImages.lean | 6 +- RealRooted/BrandenLeite/KernelClosure.lean | 6 +- RealRooted/Challenges/OperatorPreservers.lean | 10 +- RealRooted/EulerOperator.lean | 47 +++++----- RealRooted/EulerOperator/Pencil.lean | 4 +- RealRooted/HosterStump/Sequence.lean | 2 +- RealRooted/HosterStump/Step.lean | 4 +- RealRooted/Interlacing/WindowInduction.lean | 25 +++-- RealRooted/MatrixInterlacing.lean | 29 ++---- RealRooted/OperatorMatrix/Directed.lean | 3 +- RealRooted/OperatorMatrix/OneThetaX.lean | 4 +- RealRooted/PFPolynomial.lean | 9 -- .../SymmetricDecomposition/Decomposition.lean | 9 +- .../SymmetricDecomposition/Theorem26.lean | 15 ++- RealRooted/Tactic/EulerOperator.lean | 91 +++++++++++++------ RealRooted/Tactic/Examples/EulerOperator.lean | 21 +---- .../Examples/OEIS/DifferentialOperators.lean | 4 - RealRooted/Tactic/Examples/PFPolynomial.lean | 12 +-- RealRooted/Tactic/Examples/WagnerX.lean | 36 ++------ RealRooted/Tactic/Finish.lean | 2 +- RealRooted/Tactic/PFPolynomial.lean | 42 +++++---- RealRooted/Tactic/WagnerX/Frontend.lean | 20 ++-- RealRooted/Tactic/WagnerX/Syntax.lean | 27 ++++-- RealRooted/WagnerX/ListInterlacing.lean | 39 ++++++++ RealRooted/WagnerX/NonnegativeRoots.lean | 39 ++------ RealRooted/WagnerX/ProperPosition.lean | 18 +++- 29 files changed, 271 insertions(+), 282 deletions(-) diff --git a/PROOF_STATUS.md b/PROOF_STATUS.md index b21807f43..21fae6a97 100644 --- a/PROOF_STATUS.md +++ b/PROOF_STATUS.md @@ -30,7 +30,7 @@ None. | Liu theorem with common roots | `compatible_iff_rootCountBranchesWithCommon` | | Garloff--Wagner PF closure | `garloffWagnerHadamardPFInterl_of_nonnegStrictInterl` | | Bounded-degree polar-theta interlacing preservation | `polarThetaPreservesInterlStatement`, witnessed by `polarTheta_preserves_interl` | -| Theta interlacing preservation on the PF cone | `thetaPreservesInterlStatement`, witnessed by `thetaPreservesInterl` | +| Theta interlacing preservation | `thetaPreservesInterlStatement`, witnessed by `Interl.theta` | | Derivative preservation of weak interlacing | `derivativePreservesInterl` | | Nonnegative interlacing pair gives a Hurwitz-stable odd/even polynomial | `isHurwitzStable_oddEvenPolynomial_of_strictInterl` | | Hurwitz-stable odd/even polynomial gives an interlacing pair (issue #1112) | `strictInterl_of_isHurwitzStable_oddEvenPolynomial`, `isHurwitzStable_oddEvenPolynomial_iff` | diff --git a/RealRooted/AffineProperPosition.lean b/RealRooted/AffineProperPosition.lean index efa3824d1..26cef48df 100644 --- a/RealRooted/AffineProperPosition.lean +++ b/RealRooted/AffineProperPosition.lean @@ -322,18 +322,13 @@ theorem interl_affine_mul_X_self {s t : ℝ} (hs : 0 < s) : (isRealRooted_affine_factor hs).2).2 theorem interl_affine_mul_X_add_X_affine_mul_X - {s t : ℝ} (hs : 0 < s) (ht : 0 < t) : + {s t : ℝ} (hs : 0 < s) : Interl ((C s * X + C t) * X + X) ((C s * X + C t) * X) := by rw [show ((C s * X + C t) * X + X : ℝ[X]) = X * (C s * X + C (t + 1)) by grind] rw [show ((C s * X + C t) * X : ℝ[X]) = X * (C s * X + C t) by ring] - have hleft_nonneg : HasNonnegCoeffs (C s * X + C t + 1 : ℝ[X]) := by - rw [show (C s * X + C t + 1 : ℝ[X]) = C s * X + C (t + 1) by grind] - exact hasNonnegCoeffs_affine_linear hs.le (by positivity) simpa [show (C s * X + C t + 1 : ℝ[X]) = C s * X + C (t + 1) by grind] using - (interl_affine_add_one_affine (t := t) hs).mul_X_both_of_nonneg - hleft_nonneg - (hasNonnegCoeffs_affine_linear (a := s) (b := t) hs.le ht.le) + (interl_affine_add_one_affine (t := t) hs).mul_X_both theorem interl_affine_mul_X_add_X_self {s t : ℝ} (hs : 0 < s) : Interl ((C s * X + C t) * X + X) ((C s * X + C t) * X + X) := by diff --git a/RealRooted/Applications/OEIS/A304330.lean b/RealRooted/Applications/OEIS/A304330.lean index 3b150055a..3142f9c5c 100644 --- a/RealRooted/Applications/OEIS/A304330.lean +++ b/RealRooted/Applications/OEIS/A304330.lean @@ -301,23 +301,7 @@ theorem qPolynomial_strictInterl_succ (n : ℕ) : (by rw [(qPolynomial_invariants n).1]; lia) ih (qPolynomial_invariants (n + 1)).2.2 (qPolynomial_invariants n).2.2 hpout hqout hpoutdeg - simpa only [qPolynomial] using hm.thetaPlusOne_of_pf - (by - rw [mOperator_eq_bidiagonalOperator] - exact RealRooted.BorceaBranden.bidiagonalOperator_isPF_of_affineSymbol_stable - (affineBidiagonalSymbol_stable (n + 2) (by lia)) - (fun k => by unfold alpha; positivity) - (fun k => by unfold beta; positivity) - (by rw [(qPolynomial_invariants n).1]; lia) - (qPolynomial_isPF n)) - (by - rw [mOperator_eq_bidiagonalOperator] - exact RealRooted.BorceaBranden.bidiagonalOperator_isPF_of_affineSymbol_stable - (affineBidiagonalSymbol_stable (n + 2) (by lia)) - (fun k => by unfold alpha; positivity) - (fun k => by unfold beta; positivity) - (by rw [(qPolynomial_invariants (n + 1)).1]; lia) - (qPolynomial_isPF (n + 1))) + simpa only [qPolynomial] using hm.thetaPlusOne /-- The A304330 model, with its common `X` factor visible after row zero. -/ def polynomial : ℕ → ℝ[X] diff --git a/RealRooted/Applications/OEIS/TouchardImages.lean b/RealRooted/Applications/OEIS/TouchardImages.lean index 53afb65eb..d087586ab 100644 --- a/RealRooted/Applications/OEIS/TouchardImages.lean +++ b/RealRooted/Applications/OEIS/TouchardImages.lean @@ -155,11 +155,7 @@ theorem touchardEulerQuotientRow_splits (n : ℕ) : theorem touchardEulerQuotientRow_strictInterl_succ (n : ℕ) : StrictInterl (touchardEulerQuotientRow n) (touchardEulerQuotientRow (n + 1)) := by - have hstrict := (strictInterl_touchard_succ (n + 1)).thetaPlusOne_of_pf - (IsPFPolynomial.of_realRooted_nonneg - (touchard_nonnegCoeffs (n + 1)) (isRealRooted_touchard (n + 1)).2) - (IsPFPolynomial.of_realRooted_nonneg - (touchard_nonnegCoeffs (n + 2)) (isRealRooted_touchard (n + 2)).2) + have hstrict := (strictInterl_touchard_succ (n + 1)).thetaPlusOne rw [← X_mul_touchardEulerQuotientRow, ← X_mul_touchardEulerQuotientRow] at hstrict exact StrictInterl.of_mul_X_sub_C_both (r := 0) (by simpa using hstrict) diff --git a/RealRooted/BrandenLeite/KernelClosure.lean b/RealRooted/BrandenLeite/KernelClosure.lean index 3ea26ed36..ed801fe9b 100644 --- a/RealRooted/BrandenLeite/KernelClosure.lean +++ b/RealRooted/BrandenLeite/KernelClosure.lean @@ -104,11 +104,7 @@ theorem interl_regularizedKernelRow_succ (g * η) G H i.castSucc, chainPolynomial_sourceBorder_eq_X_mul_regularizedKernelRow (g * η) G H i.succ] at hchain - apply hchain.of_mul_X_both_of_nonneg - · exact (regularizedKernelRow_isPFPolynomial hg hη hG hH hGlower - hHlower hGdiag hHdiag i.castSucc).hasNonnegCoeffs - · exact (regularizedKernelRow_isPFPolynomial hg hη hG hH hGlower - hHlower hGdiag hHdiag i.succ).hasNonnegCoeffs + exact hchain.of_mul_X_both /-- Strictly lower entrywise limits of positive-diagonal TN approximations have PF kernel rows and consecutive zero-aware interlacing. -/ diff --git a/RealRooted/Challenges/OperatorPreservers.lean b/RealRooted/Challenges/OperatorPreservers.lean index 1451900b8..df7d40bd8 100644 --- a/RealRooted/Challenges/OperatorPreservers.lean +++ b/RealRooted/Challenges/OperatorPreservers.lean @@ -51,7 +51,7 @@ headline = true [[theorems]] name = "RealRooted.Challenges.OperatorPreservers.Interl.theta" -label = "θ preserves interlacing of PF polynomials" +label = "θ preserves interlacing" [[theorems]] name = "RealRooted.Challenges.OperatorPreservers.Interl.polarTheta" @@ -150,10 +150,10 @@ theorem preservesInterlacing_of_preservesRealRootedOrZero (T : ℝ[X] →ₗ[ℝ Interl (T f) (T g) ∨ Interl (T g) (T f) := RealRooted.operatorPreservesInterlacingPairsUpToOrder T hT hfg -/-- The Euler operator `θ = X d/dX` preserves interlacing of PF polynomials. -/ -theorem Interl.theta {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) - (hpq : Interl p q) : Interl (RealRooted.theta p) (RealRooted.theta q) := - thetaPreservesInterl hp hq hpq +/-- The Euler operator `θ = X d/dX` preserves interlacing. -/ +theorem Interl.theta {p q : ℝ[X]} (hpq : Interl p q) : + Interl (RealRooted.theta p) (RealRooted.theta q) := + hpq.theta /-- The polar Euler operator `N - θ` preserves interlacing of PF polynomials of degree at most `N`. -/ diff --git a/RealRooted/EulerOperator.lean b/RealRooted/EulerOperator.lean index 0e32eed9d..f6b9d194b 100644 --- a/RealRooted/EulerOperator.lean +++ b/RealRooted/EulerOperator.lean @@ -192,36 +192,44 @@ theorem thetaPreservesRealRootedOrZero {p : ℝ[X]} (hp : IsPFPolynomial p) : (theta p = 0 ∨ (theta p).Splits) ∧ ∀ r ∈ (theta p).roots, r ≤ 0 := ⟨(theta_preserves_pf hp).eq_zero_or_splits, (theta_preserves_pf hp).roots_nonpos⟩ -/-- `theta` preserves weak interlacing on the polynomial PF cone. This -proposition is proved by `thetaPreservesInterl`; the name is kept for -downstream users. -/ +/-- `theta` preserves weak interlacing. This proposition is proved by +`Interl.theta`. -/ def thetaPreservesInterlStatement : Prop := ∀ {p q : ℝ[X]}, - IsPFPolynomial p → - IsPFPolynomial q → Interl p q → Interl (theta p) (theta q) -/-- `theta` preserves weak interlacing on the polynomial PF cone, obtained +/-- `theta` preserves weak interlacing, obtained from the derivative preservation theorem and multiplication by `X`. -/ -theorem thetaPreservesInterl {p q : ℝ[X]} - (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) (hpq : Interl p q) : +theorem Interl.theta {p q : ℝ[X]} (hpq : Interl p q) : Interl (theta p) (theta q) := by - simpa [theta] using - interl_X_mul_both_of_pf hp.derivative hq.derivative (derivativePreservesInterl hpq) + simpa [RealRooted.theta] using (derivativePreservesInterl hpq).mul_X_both + +/-- Compatibility form retaining the former PF hypotheses. -/ +@[deprecated Interl.theta +typeChanged (since := "2026-10-21")] +theorem thetaPreservesInterl {p q : ℝ[X]} + (_hp : IsPFPolynomial p) (_hq : IsPFPolynomial q) (hpq : Interl p q) : + Interl (theta p) (theta q) := + hpq.theta /-- `theta + 1` preserves the polynomial PF cone. -/ theorem thetaPlusOne_preserves_pf {p : ℝ[X]} (hp : IsPFPolynomial p) : IsPFPolynomial (thetaPlusOne p) := by simpa [thetaPlusOne_eq_derivative_X_mul] using hp.X_mul.derivative -/-- `theta + 1` preserves weak interlacing on the polynomial PF cone, obtained +/-- `theta + 1` preserves weak interlacing, obtained from the derivative preservation theorem. -/ -theorem thetaPlusOnePreservesInterl {p q : ℝ[X]} - (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) (hpq : Interl p q) : +theorem Interl.thetaPlusOne {p q : ℝ[X]} (hpq : Interl p q) : Interl (thetaPlusOne p) (thetaPlusOne q) := by simpa [thetaPlusOne_eq_derivative_X_mul] using - derivativePreservesInterl (interl_X_mul_both_of_pf hp hq hpq) + derivativePreservesInterl hpq.mul_X_both + +/-- Compatibility form retaining the former PF hypotheses. -/ +@[deprecated Interl.thetaPlusOne +typeChanged (since := "2026-10-21")] +theorem thetaPlusOnePreservesInterl {p q : ℝ[X]} + (_hp : IsPFPolynomial p) (_hq : IsPFPolynomial q) (hpq : Interl p q) : + Interl (thetaPlusOne p) (thetaPlusOne q) := + hpq.thetaPlusOne /-- A PF polynomial need not interlace its iterates under `theta + 1`: for `p = (X + 2) (X + 3)`, `(theta + 1)^2 p = 9X² + 20X + 6` has both roots in `(-2, 0)`, to the @@ -350,17 +358,12 @@ theorem iterateThetaPlusOne_preserves_pf simpa [iterateThetaPlusOne_succ] using thetaPlusOne_preserves_pf (ih hp) /-- `Interl` preservation for the `l`-fold iterate of `theta + 1`. -/ -theorem iterateThetaPlusOne_preserves_interl - (l : ℕ) {p q : ℝ[X]} - (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) (hpq : Interl p q) : +theorem Interl.iterateThetaPlusOne {p q : ℝ[X]} (hpq : Interl p q) (l : ℕ) : Interl (iterateThetaPlusOne l p) (iterateThetaPlusOne l q) := by - induction l generalizing p q with + induction l with | zero => simpa using hpq | succ l ih => - simpa [iterateThetaPlusOne_succ] using thetaPlusOnePreservesInterl - (iterateThetaPlusOne_preserves_pf l hp) - (iterateThetaPlusOne_preserves_pf l hq) - (ih hp hq hpq) + simpa [iterateThetaPlusOne_succ] using ih.thetaPlusOne end RealRooted diff --git a/RealRooted/EulerOperator/Pencil.lean b/RealRooted/EulerOperator/Pencil.lean index 2f5254e6a..5bdb6a8b8 100644 --- a/RealRooted/EulerOperator/Pencil.lean +++ b/RealRooted/EulerOperator/Pencil.lean @@ -23,9 +23,9 @@ theorem strictInterl_thetac_X_mul {f : ℝ[X]} (hf : IsPFPolynomial f) intro hzero simp_all have hfs : f ≠ 0 ∧ f.Splits := hf.ne_zero_and_splits hf0 - have hnn : HasNonnegCoeffs f := hf.hasNonnegCoeffs have hleft : StrictInterl (X * f.derivative) (X * f) := - strictInterl_X_derivative_X_self_of_splits_nonneg hfs.2 hdeg hnn + strictInterl_X_derivative_X_self_of_splits hfs.2 hdeg + have hnn : HasNonnegCoeffs f := hf.hasNonnegCoeffs have hself : StrictInterl f (X * f) := strictInterl_self_X_mul_of_nonneg hfs.1 hfs.2 hnn have hright : StrictInterl (C c * f) (X * f) := StrictInterl.C_mul_left hself hc.ne' have hfd_ne : f.derivative ≠ 0 := diff --git a/RealRooted/HosterStump/Sequence.lean b/RealRooted/HosterStump/Sequence.lean index 984458e93..6378e94ba 100644 --- a/RealRooted/HosterStump/Sequence.lean +++ b/RealRooted/HosterStump/Sequence.lean @@ -226,7 +226,7 @@ private theorem interl_X_mul_add_add_X_mul {P M W : ℝ[X]} (hPM : Interl P M) have key := Interl.window_three (f₁ := M) (f₂ := W) (f₃ := X * P) (f₄ := X * M) hMW (interl_mul_X_of_interl hPM nnP nnM) (interl_mul_X_of_interl (Interl.refl sM) nnM nnM) (interl_mul_X_of_interl hMW nnM nnW) - (hPM.mul_X_both_of_nonneg nnP nnM) nnM nnW nnP.X_mul + hPM.mul_X_both nnM nnW nnP.X_mul nnM.X_mul (splits_add_X_mul_of_interl hPW nnP nnW sP sW) rw [show X * P + (M + W) = M + W + X * P by ring, show X * (P + M) + W = W + X * P + X * M by ring] diff --git a/RealRooted/HosterStump/Step.lean b/RealRooted/HosterStump/Step.lean index 55156443d..26436e127 100644 --- a/RealRooted/HosterStump/Step.lean +++ b/RealRooted/HosterStump/Step.lean @@ -147,7 +147,7 @@ private theorem Lvl.top_row (h : Lvl n A B C) {i j : ℕ} (hij : i < j) (hj : j private theorem Lvl.bot_row (h : Lvl n A B C) {i j : ℕ} (hij : i < j) (hj : j ≤ n + 1) : Interl (X * ∑ k ∈ Finset.range i, A k) (X * ∑ k ∈ Finset.range j, A k) := by - refine Interl.mul_X_both_of_nonneg ?_ (h.nnSA _) (h.nnSA _) + apply Interl.mul_X_both rw [← Finset.sum_range_add_sum_Ico A hij.le] refine interl_add_right_of_common_left_of_nonneg (Interl.refl (h.splitsSA (by lia))) ?_ (h.nnSA _) (h.nnSA _) @@ -217,7 +217,7 @@ private theorem Lvl.mid_cons (h : Lvl n A B C) {k : ℕ} (hk : k ≤ n) : exact Interl.finsetSum_left_of_nonneg _ _ _ (fun j hj => h.AB k j (by have := Finset.mem_Ico.1 hj; lia) (by have := Finset.mem_Ico.1 hj; lia)) fun _ _ => h.nnB _ - · refine Interl.mul_X_both_of_nonneg ?_ (h.nnSA _) (h.nnA k) + · apply Interl.mul_X_both exact Interl.finsetSum_right_of_nonneg _ _ _ (fun l hl => h.rowA l k (by have := Finset.mem_range.1 hl; lia) hk) fun _ _ => h.nnA _ · exact splits_add_of_interl hWP (h.nnSB _) (h.nnSA _).X_mul (h.splitsSB (by lia)) diff --git a/RealRooted/Interlacing/WindowInduction.lean b/RealRooted/Interlacing/WindowInduction.lean index 3b83eccb2..af6f43636 100644 --- a/RealRooted/Interlacing/WindowInduction.lean +++ b/RealRooted/Interlacing/WindowInduction.lean @@ -190,29 +190,26 @@ theorem thetaPlusOne_ne_zero_of_ne_zero {p : ℝ[X]} (hp : p ≠ 0) : rw [hzero, coeff_zero] at hcoeff exact hcoeff rfl -/-- `thetaPlusOne` preserves a directed nonzero PF interlacing edge. -/ -theorem StrictInterl.thetaPlusOne_of_pf {p q : ℝ[X]} - (h : StrictInterl p q) (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) : +/-- `thetaPlusOne` preserves a directed nonzero interlacing edge. -/ +theorem StrictInterl.thetaPlusOne {p q : ℝ[X]} (h : StrictInterl p q) : StrictInterl (thetaPlusOne p) (thetaPlusOne q) := by - have hinterl := thetaPlusOnePreservesInterl hp hq h.toInterl + have hinterl := h.toInterl.thetaPlusOne rcases hinterl with hp0 | hq0 | hstrict · exact absurd hp0 (thetaPlusOne_ne_zero_of_ne_zero h.1.1) · exact absurd hq0 (thetaPlusOne_ne_zero_of_ne_zero h.2.1.1) · exact hstrict /-- Applying `theta + 1` to a polar comparison preserves strict interlacing. -/ -theorem StrictInterl.polarTheta_thetaPlusOne_of_pf {N : ℕ} {p q : ℝ[X]} - (h : StrictInterl (polarTheta N p) q) (hp : IsPFPolynomial p) - (hq : IsPFPolynomial q) (hdeg : p.natDegree ≤ N) : - StrictInterl (polarTheta N (thetaPlusOne p)) (thetaPlusOne q) := by +theorem StrictInterl.polarTheta_thetaPlusOne {N : ℕ} {p q : ℝ[X]} + (h : StrictInterl (polarTheta N p) q) : + StrictInterl (polarTheta N (RealRooted.thetaPlusOne p)) (RealRooted.thetaPlusOne q) := by rw [polarTheta_thetaPlusOne_comm] - exact h.thetaPlusOne_of_pf (polarTheta_preserves_pf hp hdeg) hq + exact h.thetaPlusOne -/-- `thetaPlusOne` preserves a differ-by-one PF interlacing edge. -/ -theorem Interlaces.thetaPlusOne_of_pf {p q : ℝ[X]} - (h : Interlaces p q) (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) : - Interlaces (thetaPlusOne p) (thetaPlusOne q) := by - apply (h.toStrictInterl.thetaPlusOne_of_pf hp hq).toInterlaces +/-- `thetaPlusOne` preserves a differ-by-one interlacing edge. -/ +theorem Interlaces.thetaPlusOne {p q : ℝ[X]} (h : Interlaces p q) : + Interlaces (RealRooted.thetaPlusOne p) (RealRooted.thetaPlusOne q) := by + apply h.toStrictInterl.thetaPlusOne.toInterlaces rw [natDegree_thetaPlusOne_of_ne_zero h.2.1.1, natDegree_thetaPlusOne_of_ne_zero h.1.1] exact h.2.2.1 diff --git a/RealRooted/MatrixInterlacing.lean b/RealRooted/MatrixInterlacing.lean index b251a09a1..1c0335084 100644 --- a/RealRooted/MatrixInterlacing.lean +++ b/RealRooted/MatrixInterlacing.lean @@ -275,7 +275,7 @@ theorem hasAffineProperty_of_isAffineAdmissible | with_reducible exact interl_affine_add_one_affine_mul_X_add_X hs ht | with_reducible exact interl_affine_add_X_affine_mul_X_add_X hs ht | with_reducible exact interl_affine_mul_X_self hs - | with_reducible exact interl_affine_mul_X_add_X_affine_mul_X hs ht + | with_reducible exact interl_affine_mul_X_add_X_affine_mul_X hs | with_reducible exact interl_affine_mul_X_add_X_self hs /-! ### Exact obstructions for the excluded codes -/ @@ -441,14 +441,7 @@ private lemma not_interl_bad_quadratic_pair : have hfactor : Interl (X * (X + 1) : ℝ[X]) (X * (X + 2)) := by convert h using 1 <;> ring have hreduced : Interl (X + 1 : ℝ[X]) (X + 2) := by - apply Interl.of_mul_X_both_of_nonneg - · exact hfactor - · convert hasNonnegCoeffs_affine_linear - (a := 1) (b := 1) (by norm_num) (by norm_num) using 1 - simp only [C_1, one_mul] - · convert hasNonnegCoeffs_affine_linear - (a := 1) (b := 2) (by norm_num) (by norm_num) using 1 - simp only [Polynomial.C_ofNat, C_1, one_mul] + exact hfactor.of_mul_X_both have hcross := affine_cross_of_interl (u := 1) (v := 1) (U := 1) (V := 2) zero_lt_one zero_lt_one (by @@ -738,30 +731,24 @@ private theorem not_interl_X_sq_X_add_X_sq : ¬ Interl (X ^ 2 : ℝ[X]) (X + X ^ 2) := by intro h have hreduced : Interl X (1 + X) := by - apply Interl.of_mul_X_both_of_nonneg - · convert h using 1 <;> ring - · exact hasNonnegCoeffs_X - · exact hasNonnegCoeffs_one.add hasNonnegCoeffs_X + apply Interl.of_mul_X_both + convert h using 1 <;> ring exact not_interl_X_X_add_one (by simpa [add_comm] using hreduced) private theorem not_interl_X_cube_X_sq_add_X_cube : ¬ Interl (X ^ 3 : ℝ[X]) (X ^ 2 + X ^ 3) := by intro h have hreduced : Interl (X ^ 2 : ℝ[X]) (X + X ^ 2) := by - apply Interl.of_mul_X_both_of_nonneg - · convert h using 1 <;> ring - · exact nonneg_X_sq - · exact hasNonnegCoeffs_X.add nonneg_X_sq + apply Interl.of_mul_X_both + convert h using 1 <;> ring exact not_interl_X_sq_X_add_X_sq hreduced private theorem not_interl_X_add_X_sq_X_cube : ¬ Interl (X + X ^ 2 : ℝ[X]) (X ^ 3) := by intro h have hreduced : Interl (1 + X : ℝ[X]) (X ^ 2) := by - apply Interl.of_mul_X_both_of_nonneg - · convert h using 1 <;> ring - · exact hasNonnegCoeffs_one.add hasNonnegCoeffs_X - · exact nonneg_X_sq + apply Interl.of_mul_X_both + convert h using 1 <;> ring have hstrict := hreduced.toStrictInterl_of_ne (ne_zero_of_natDegree_eq_succ (by compute_degree!)) (pow_ne_zero 2 X_ne_zero) diff --git a/RealRooted/OperatorMatrix/Directed.lean b/RealRooted/OperatorMatrix/Directed.lean index b1c790e82..7d6e8af68 100644 --- a/RealRooted/OperatorMatrix/Directed.lean +++ b/RealRooted/OperatorMatrix/Directed.lean @@ -202,8 +202,7 @@ theorem IsPFPolynomial.interl_derivative_self {p : ℝ[X]} (hp : IsPFPolynomial /-- The Euler derivative of a PF polynomial precedes its product by `X`. -/ theorem IsPFPolynomial.interl_theta_X_mul {p : ℝ[X]} (hp : IsPFPolynomial p) : Interl (theta p) (X * p) := by - simpa [theta] using interl_X_mul_both_of_pf hp.derivative hp - hp.interl_derivative_self + simpa [theta] using hp.interl_derivative_self.mul_X_both /-- Zero-aware `X`-duality for PF polynomials. -/ theorem interl_iff_interl_X_mul {p q : ℝ[X]} diff --git a/RealRooted/OperatorMatrix/OneThetaX.lean b/RealRooted/OperatorMatrix/OneThetaX.lean index 3230118c2..2afe460c7 100644 --- a/RealRooted/OperatorMatrix/OneThetaX.lean +++ b/RealRooted/OperatorMatrix/OneThetaX.lean @@ -704,7 +704,7 @@ private theorem interl_X_mul_add_X_mul_add_X_mul {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) (hpq : Interl p q) : Interl (X * p + q) (X * p + X * q) := by - have hXpXq : Interl (X * p) (X * q) := interl_X_mul_both_of_pf hp hq hpq + have hXpXq : Interl (X * p) (X * q) := hpq.mul_X_both have hqXp : Interl q (X * p) := (interl_iff_interl_X_mul hp hq).mp hpq have hqXq : Interl q (X * q) := (interl_iff_interl_X_mul hq hq).mp hq.interl_self @@ -723,7 +723,7 @@ private theorem interl_theta_add_X_mul_add_theta Interl (RealRooted.theta p + q) (X * p + RealRooted.theta q) := by have hthetaP_Xp : Interl (RealRooted.theta p) (X * p) := hp.interl_theta_X_mul have hthetaP_thetaQ : Interl (RealRooted.theta p) (RealRooted.theta q) := - thetaPreservesInterl hp hq hpq + hpq.theta have hqXp : Interl q (X * p) := (interl_iff_interl_X_mul hp hq).mp hpq have hqthetaQ : Interl q (RealRooted.theta q) := hq.interl_theta have hthetaP_out : Interl (RealRooted.theta p) (X * p + RealRooted.theta q) := diff --git a/RealRooted/PFPolynomial.lean b/RealRooted/PFPolynomial.lean index 54df4318b..fed0b093d 100644 --- a/RealRooted/PFPolynomial.lean +++ b/RealRooted/PFPolynomial.lean @@ -361,15 +361,6 @@ theorem isPFPolynomial_reverse_prod_X_sub_C isPFPolynomial_X_add_C (a := -r) (neg_nonneg.mpr (hs r (by simp))) exact hr.mul (ih fun x hx => hs x (by simp [hx])) -theorem interl_X_mul_both_of_pf {p q : ℝ[X]} - (_hp : IsPFPolynomial p) (_hq : IsPFPolynomial q) - (hpq : Interl p q) : - Interl (X * p) (X * q) := by - rcases hpq with hp0 | hq0 | hpq' - · simpa [hp0] using interl_zero_left (X * q) - · simpa [hq0] using interl_zero_right (X * p) - · exact (by simpa using hpq'.mul_X_sub_C_both 0 : StrictInterl (X * p) (X * q)).toInterl - /-- Fixed-left cone closure in the two-summand form used downstream: if a polynomial is a common left interleaver for two nonnegative-coefficient summands, it is also a common left interleaver for their sum. -/ diff --git a/RealRooted/SymmetricDecomposition/Decomposition.lean b/RealRooted/SymmetricDecomposition/Decomposition.lean index ec5ccd4b7..449fd8f8f 100644 --- a/RealRooted/SymmetricDecomposition/Decomposition.lean +++ b/RealRooted/SymmetricDecomposition/Decomposition.lean @@ -172,15 +172,12 @@ lemma idTransform_X_mul_of_natDegree_le_two_pred {d : ℕ} {p : ℝ[X]} _ = X * idTransform (d - 2) p := idTransform_of_natDegree_le_pred (d := d - 1) (by lia) (by lia) +/-- Compatibility form of the common-`X` strict-interlacing equivalence. -/ +@[deprecated StrictInterl.mul_X_sub_C_both_iff +typeChanged (since := "2026-10-21")] theorem strictInterl_iff_strictInterl_mul_X_both_of_hasNonnegCoeffs {f g : ℝ[X]} (_hfnn : HasNonnegCoeffs f) (_hgnn : HasNonnegCoeffs g) : StrictInterl f g ↔ StrictInterl (X * f) (X * g) := by - constructor - · intro h - simpa using h.mul_X_sub_C_both 0 - · intro h - apply StrictInterl.of_mul_X_sub_C_both (r := 0) - simpa using h + simpa using StrictInterl.mul_X_sub_C_both_iff (f := f) (g := g) 0 lemma hasNonnegCoeffs_of_eq_X_mul {p q : ℝ[X]} (hp : HasNonnegCoeffs p) (h : p = X * q) : diff --git a/RealRooted/SymmetricDecomposition/Theorem26.lean b/RealRooted/SymmetricDecomposition/Theorem26.lean index acd4a6c3c..17f57de0e 100644 --- a/RealRooted/SymmetricDecomposition/Theorem26.lean +++ b/RealRooted/SymmetricDecomposition/Theorem26.lean @@ -850,11 +850,10 @@ theorem BrandenSolus.last_equiv (idTransform_natDegree_le hd) hd hId_nonneg hp_nonneg).symm private lemma strictInterl_iff_of_eq_X_mul - {f g f' g' : ℝ[X]} (hf : f = X * f') (hg : g = X * g') - (hfnn : HasNonnegCoeffs f') (hgnn : HasNonnegCoeffs g') : + {f g f' g' : ℝ[X]} (hf : f = X * f') (hg : g = X * g') : StrictInterl f g ↔ StrictInterl f' g' := by - simpa only [hf, hg] using - (strictInterl_iff_strictInterl_mul_X_both_of_hasNonnegCoeffs hfnn hgnn).symm + simpa [hf, hg] using + (StrictInterl.mul_X_sub_C_both_iff (f := f') (g := g') 0).symm private theorem BrandenSolus.descend_of_lt_top {d : ℕ} {p a b : ℝ[X]} @@ -910,12 +909,12 @@ private theorem BrandenSolus.descend_of_lt_top idTransform_X_mul_of_natDegree_le_two_pred hd2 hqdeg have hsmall := hprev hqdeg hidq ha'_nonneg hb'_nonneg ha'0 hb'0 rcases hsmall with ⟨hfirst_small, hsecond_small, hthird_small, -⟩ - have hba_transport := strictInterl_iff_of_eq_X_mul hbX haX hb'_nonneg ha'_nonneg - have hap_transport := strictInterl_iff_of_eq_X_mul haX hpX' ha'_nonneg hq_nonneg - have hbp_transport := strictInterl_iff_of_eq_X_mul hbX hpX' hb'_nonneg hq_nonneg + have hba_transport := strictInterl_iff_of_eq_X_mul hbX haX + have hap_transport := strictInterl_iff_of_eq_X_mul haX hpX' + have hbp_transport := strictInterl_iff_of_eq_X_mul hbX hpX' have hIdp_transport : StrictInterl (idTransform d p) p ↔ StrictInterl (idTransform (d - 2) q) q := - strictInterl_iff_of_eq_X_mul hIdX hpX' hIdq_nonneg hq_nonneg + strictInterl_iff_of_eq_X_mul hIdX hpX' refine ⟨?_, ?_, ?_, BrandenSolus.last_equiv hd hid ha_nonneg hb_nonneg⟩ <;> lia /-- The naive fully strict translation of Brändén--Solus Theorem 2.6, without diff --git a/RealRooted/Tactic/EulerOperator.lean b/RealRooted/Tactic/EulerOperator.lean index 1eb06d3b1..87a70864c 100644 --- a/RealRooted/Tactic/EulerOperator.lean +++ b/RealRooted/Tactic/EulerOperator.lean @@ -105,22 +105,16 @@ theorem iterateThetaPlusOne_sequence_pf RealRooted.iterateThetaPlusOne_preserves_pf (l i) (hP i) theorem thetaPlusOne_sequence_interl - {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) - (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : + {P Q : Nat → ℝ[X]} (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (thetaPlusOne (P i)) (thetaPlusOne (Q i)) := fun i => - RealRooted.thetaPlusOnePreservesInterl (hP i) (hQ i) (hPQ i) + (hPQ i).thetaPlusOne theorem iterateThetaPlusOne_sequence_interl - {l : Nat → Nat} {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) - (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : + {l : Nat → Nat} {P Q : Nat → ℝ[X]} (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (iterateThetaPlusOne (l i) (P i)) (iterateThetaPlusOne (l i) (Q i)) := fun i => - RealRooted.iterateThetaPlusOne_preserves_interl (l i) (hP i) (hQ i) (hPQ i) + (hPQ i).iterateThetaPlusOne (l i) /-- Closes `HasNonnegCoeffs (theta p)` from `nonneg : HasNonnegCoeffs p`. -/ syntax (name := rr_theta_nonneg_named) @@ -210,26 +204,41 @@ syntax (name := rr_iterateThetaPlusOne_sequence_pf_named) "pf" ":=" term : tactic -/-- Closes `Interl (thetaPlusOne p) (thetaPlusOne q)` from `left_pf : IsPFPolynomial p`, -`right_pf : IsPFPolynomial q` and `interl : Interl p q`. -/ +/-- Closes `Interl (thetaPlusOne p) (thetaPlusOne q)` from `interl : Interl p q`. +The former PF-certificate fields remain accepted for compatibility. -/ syntax (name := rr_thetaPlusOne_interl_named) + "rr_thetaPlusOne_interl" " using " "interl" ":=" term : + tactic + +syntax (name := rr_thetaPlusOne_interl_compat_named) "rr_thetaPlusOne_interl" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," "interl" ":=" term : tactic -/-- Sequence form of `rr_thetaPlusOne_interl`: the same certificate for every index `i`. -/ +/-- Sequence form of `rr_thetaPlusOne_interl`: the same certificate for every +index `i`. The former PF-certificate fields remain accepted. -/ syntax (name := rr_thetaPlusOne_sequence_interl_named) + "rr_thetaPlusOne_sequence_interl" " using " "interl" ":=" term : + tactic + +syntax (name := rr_thetaPlusOne_sequence_interl_compat_named) "rr_thetaPlusOne_sequence_interl" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," "interl" ":=" term : tactic -/-- Closes `Interl (iterateThetaPlusOne l p) (iterateThetaPlusOne l q)` from `index : l`, -`left_pf : IsPFPolynomial p`, `right_pf : IsPFPolynomial q` and `interl : Interl p q`. -/ +/-- Closes `Interl (iterateThetaPlusOne l p) (iterateThetaPlusOne l q)` from +`index : l` and `interl : Interl p q`. The former PF-certificate fields remain accepted. -/ syntax (name := rr_iterateThetaPlusOne_interl_named) + "rr_iterateThetaPlusOne_interl" " using " + "index" ":=" term "," + "interl" ":=" term : + tactic + +syntax (name := rr_iterateThetaPlusOne_interl_compat_named) "rr_iterateThetaPlusOne_interl" " using " "index" ":=" term "," "left_pf" ":=" term "," @@ -237,9 +246,15 @@ syntax (name := rr_iterateThetaPlusOne_interl_named) "interl" ":=" term : tactic -/-- Sequence form of `rr_iterateThetaPlusOne_interl`: the same certificate for every index `i`, -with `l i` in place of `l`. -/ +/-- Sequence form of `rr_iterateThetaPlusOne_interl`: the same certificate for +every index `i`, with `l i` in place of `l`. The former PF fields remain accepted. -/ syntax (name := rr_iterateThetaPlusOne_sequence_interl_named) + "rr_iterateThetaPlusOne_sequence_interl" " using " + "index" ":=" term "," + "interl" ":=" term : + tactic + +syntax (name := rr_iterateThetaPlusOne_sequence_interl_compat_named) "rr_iterateThetaPlusOne_sequence_interl" " using " "index" ":=" term "," "left_pf" ":=" term "," @@ -317,34 +332,52 @@ macro_rules index := $l:term, pf := $hp:term) => `(tactic| exact RealRooted.Tactic.iterateThetaPlusOne_sequence_pf (l := $l) $hp) + | `(tactic| + rr_thetaPlusOne_interl using interl := $hpq:term) => + `(tactic| exact RealRooted.Interl.thetaPlusOne $hpq) | `(tactic| rr_thetaPlusOne_interl using - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, interl := $hpq:term) => - `(tactic| exact RealRooted.thetaPlusOnePreservesInterl $hp $hq $hpq) + `(tactic| exact RealRooted.Interl.thetaPlusOne $hpq) + | `(tactic| + rr_thetaPlusOne_sequence_interl using interl := $hpq:term) => + `(tactic| exact RealRooted.Tactic.thetaPlusOne_sequence_interl $hpq) | `(tactic| rr_thetaPlusOne_sequence_interl using - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, + interl := $hpq:term) => + `(tactic| exact RealRooted.Tactic.thetaPlusOne_sequence_interl $hpq) + | `(tactic| + rr_iterateThetaPlusOne_interl using + index := $l:term, interl := $hpq:term) => - `(tactic| exact RealRooted.Tactic.thetaPlusOne_sequence_interl $hp $hq $hpq) + `(tactic| exact RealRooted.Interl.iterateThetaPlusOne $hpq $l) | `(tactic| rr_iterateThetaPlusOne_interl using index := $l:term, - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, interl := $hpq:term) => - `(tactic| exact RealRooted.iterateThetaPlusOne_preserves_interl $l $hp $hq $hpq) + `(tactic| exact RealRooted.Interl.iterateThetaPlusOne $hpq $l) + | `(tactic| + rr_iterateThetaPlusOne_sequence_interl using + index := $l:term, + interl := $hpq:term) => + `(tactic| + exact RealRooted.Tactic.iterateThetaPlusOne_sequence_interl + (l := $l) $hpq) | `(tactic| rr_iterateThetaPlusOne_sequence_interl using index := $l:term, - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, interl := $hpq:term) => `(tactic| exact RealRooted.Tactic.iterateThetaPlusOne_sequence_interl - (l := $l) $hp $hq $hpq) + (l := $l) $hpq) end Tactic end RealRooted diff --git a/RealRooted/Tactic/Examples/EulerOperator.lean b/RealRooted/Tactic/Examples/EulerOperator.lean index 9e35adef5..06c70d53c 100644 --- a/RealRooted/Tactic/Examples/EulerOperator.lean +++ b/RealRooted/Tactic/Examples/EulerOperator.lean @@ -91,40 +91,27 @@ example {l : Nat → Nat} {P : Nat → ℝ[X]} index := l, pf := hP -example {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) - (hpq : Interl p q) : +example {p q : ℝ[X]} (hpq : Interl p q) : Interl (thetaPlusOne p) (thetaPlusOne q) := by - rr_thetaPlusOne_interl using left_pf := hp, right_pf := hq, interl := hpq + rr_thetaPlusOne_interl using interl := hpq example {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (thetaPlusOne (P i)) (thetaPlusOne (Q i)) := by - rr_thetaPlusOne_sequence_interl using - left_pf := hP, - right_pf := hQ, - interl := hPQ + rr_thetaPlusOne_sequence_interl using interl := hPQ -example {l : ℕ} {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) - (hpq : Interl p q) : +example {l : ℕ} {p q : ℝ[X]} (hpq : Interl p q) : Interl (iterateThetaPlusOne l p) (iterateThetaPlusOne l q) := by rr_iterateThetaPlusOne_interl using index := l, - left_pf := hp, - right_pf := hq, interl := hpq example {l : Nat → Nat} {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (iterateThetaPlusOne (l i) (P i)) (iterateThetaPlusOne (l i) (Q i)) := by rr_iterateThetaPlusOne_sequence_interl using index := l, - left_pf := hP, - right_pf := hQ, interl := hPQ end Tactic diff --git a/RealRooted/Tactic/Examples/OEIS/DifferentialOperators.lean b/RealRooted/Tactic/Examples/OEIS/DifferentialOperators.lean index 4901dab58..4c185e78a 100644 --- a/RealRooted/Tactic/Examples/OEIS/DifferentialOperators.lean +++ b/RealRooted/Tactic/Examples/OEIS/DifferentialOperators.lean @@ -23,15 +23,11 @@ example {P : Nat → ℝ[X]} /-- Iterated Euler-operator proper-position row-family exit exposed through the OEIS facade. -/ example {l : Nat → Nat} {P Q : Nat → ℝ[X]} - (hP : ∀ n : Nat, IsPFPolynomial (P n)) - (hQ : ∀ n : Nat, IsPFPolynomial (Q n)) (hPQ : ∀ n : Nat, Interl (P n) (Q n)) : ∀ n : Nat, Interl (iterateThetaPlusOne (l n) (P n)) (iterateThetaPlusOne (l n) (Q n)) := by rr_iterateThetaPlusOne_sequence_interl using index := l, - left_pf := hP, - right_pf := hQ, interl := hPQ /-- Derivative-shift row-family real-rootedness exit exposed through the OEIS diff --git a/RealRooted/Tactic/Examples/PFPolynomial.lean b/RealRooted/Tactic/Examples/PFPolynomial.lean index 58becdacc..8a73bfe95 100644 --- a/RealRooted/Tactic/Examples/PFPolynomial.lean +++ b/RealRooted/Tactic/Examples/PFPolynomial.lean @@ -230,20 +230,14 @@ example {P : Nat → ℝ[X]} ∀ i : Nat, Interl (P i) (P i) := by rr_pf_sequence_interl_self using pf := hP -example {p q : ℝ[X]} (hp : IsPFPolynomial p) (hq : IsPFPolynomial q) - (hpq : Interl p q) : +example {p q : ℝ[X]} (hpq : Interl p q) : Interl (X * p) (X * q) := by - rr_pf_interl_X_mul_both using left_pf := hp, right_pf := hq, interl := hpq + rr_pf_interl_X_mul_both using interl := hpq example {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (X * P i) (X * Q i) := by - rr_pf_sequence_interl_X_mul_both using - left_pf := hP, - right_pf := hQ, - interl := hPQ + rr_pf_sequence_interl_X_mul_both using interl := hPQ end Tactic end RealRooted diff --git a/RealRooted/Tactic/Examples/WagnerX.lean b/RealRooted/Tactic/Examples/WagnerX.lean index a86b612d5..27e0e1ef3 100644 --- a/RealRooted/Tactic/Examples/WagnerX.lean +++ b/RealRooted/Tactic/Examples/WagnerX.lean @@ -40,22 +40,12 @@ example {f g : ℝ[X]} StrictInterl g (X * f) := by rr_strict_interl_mul_X -/-- Narayana/singleton-free-set-partition style common `X` factor: -nonnegative coefficients discharge the root-nonpositive side conditions. -/ -example {f g : ℝ[X]} - (hfg : StrictInterl f g) - (hfnn : HasNonnegCoeffs f) - (hgnn : HasNonnegCoeffs g) : +/-- Narayana/singleton-free-set-partition style common `X` factor. -/ +example {f g : ℝ[X]} (hfg : StrictInterl f g) : StrictInterl (X * f) (X * g) := by - rr_strict_interl_mul_X_both using - proper := hfg, - left_nonneg := hfnn, - right_nonneg := hgnn + rr_strict_interl_mul_X_both using proper := hfg -example {f g : ℝ[X]} - (hfg : StrictInterl f g) - (hfnn : HasNonnegCoeffs f) - (hgnn : HasNonnegCoeffs g) : +example {f g : ℝ[X]} (hfg : StrictInterl f g) : StrictInterl (X * f) (X * g) := by rr_strict_interl_mul_X_both @@ -99,22 +89,18 @@ example {f g : ℝ[X]} {c : ℝ} StrictInterl g ((C c * X) * f) := by rr_strict_interl_C_mul_X using coeff_pos := hc -/-- Derivative-lag bridge: a nonnegative real-rooted row gives -`X * P'_n ≪ X * P_n`. -/ +/-- Derivative-lag bridge: a split row gives `X * P'_n ≪ X * P_n`. -/ example {f : ℝ[X]} (hf : f.Splits) - (hdeg : 2 ≤ f.natDegree) - (hfnn : HasNonnegCoeffs f) : + (hdeg : 2 ≤ f.natDegree) : StrictInterl (X * f.derivative) (X * f) := by rr_strict_interl_X_derivative_X_self using splits := hf, - degree_two := hdeg, - nonneg_coeffs := hfnn + degree_two := hdeg example {f : ℝ[X]} (hf : f.Splits) - (hdeg : 2 ≤ f.natDegree) - (hfnn : HasNonnegCoeffs f) : + (hdeg : 2 ≤ f.natDegree) : StrictInterl (X * f.derivative) (X * f) := by rr_strict_interl_X_derivative_X_self @@ -758,12 +744,8 @@ lemma a358623Shifted_base : StrictInterl (a358623Shifted 0) (a358623Shifted 1) : have hlin : Interlaces (1 : ℝ[X]) (1 + C (3 : ℝ) * X) := interlaces_one_linear (by simp) have hstrictInterl : StrictInterl (1 : ℝ[X]) (1 + C (3 : ℝ) * X) := hlin.toStrictInterl - have hlin_nonneg : HasNonnegCoeffs (1 + C (3 : ℝ) * X) := by rr_nonneg_coeffs have hmul : StrictInterl (X * (1 : ℝ[X])) (X * (1 + C (3 : ℝ) * X)) := by - rr_strict_interl_mul_X_both using - proper := hstrictInterl, - left_nonneg := hasNonnegCoeffs_one, - right_nonneg := hlin_nonneg + rr_strict_interl_mul_X_both using proper := hstrictInterl simpa using hmul /-- Nonnegative coefficients for every shifted `A358623` active row. -/ diff --git a/RealRooted/Tactic/Finish.lean b/RealRooted/Tactic/Finish.lean index f51fead30..f6da67338 100644 --- a/RealRooted/Tactic/Finish.lean +++ b/RealRooted/Tactic/Finish.lean @@ -1026,7 +1026,7 @@ macro_rules | rr_zero_or_splits using rr_lookup_term | assumption | (apply Or.inr; apply Polynomial.Splits.mul <;> - apply splits_of_eq_zero_or_splits; rr_zero_or_splits) + (apply splits_of_eq_zero_or_splits; rr_zero_or_splits)) | (apply Or.inr; apply Polynomial.Splits.pow; apply splits_of_eq_zero_or_splits; rr_zero_or_splits) -- `apply` rejects a non-disjunction before `rr_splits` runs; `exact Or.inr (by …)` diff --git a/RealRooted/Tactic/PFPolynomial.lean b/RealRooted/Tactic/PFPolynomial.lean index e8a1d8e41..775ccf0fb 100644 --- a/RealRooted/Tactic/PFPolynomial.lean +++ b/RealRooted/Tactic/PFPolynomial.lean @@ -161,13 +161,10 @@ theorem pf_sequence_interl_self ∀ i : Nat, Interl (P i) (P i) := fun i => RealRooted.IsPFPolynomial.interl_self (hP i) -theorem pf_sequence_interl_X_mul_both - {P Q : Nat → ℝ[X]} - (hP : ∀ i : Nat, IsPFPolynomial (P i)) - (hQ : ∀ i : Nat, IsPFPolynomial (Q i)) - (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : +theorem interl_sequence_mul_X_both + {P Q : Nat → ℝ[X]} (hPQ : ∀ i : Nat, Interl (P i) (Q i)) : ∀ i : Nat, Interl (X * P i) (X * Q i) := fun i => - RealRooted.interl_X_mul_both_of_pf (hP i) (hQ i) (hPQ i) + (hPQ i).mul_X_both /-- Closes `IsPFPolynomial 0`. -/ syntax (name := rr_pf_zero_named) "rr_pf_zero" : tactic @@ -414,17 +411,26 @@ syntax (name := rr_pf_sequence_interl_self_named) "rr_pf_sequence_interl_self" " using " "pf" ":=" term : tactic -/-- Closes `Interl (X * p) (X * q)` from `left_pf : IsPFPolynomial p`, `right_pf : IsPFPolynomial q` -and `interl : Interl p q`. -/ +/-- Closes `Interl (X * p) (X * q)` from `interl : Interl p q`. +The former `left_pf`, `right_pf`, `interl` syntax remains accepted for compatibility. -/ syntax (name := rr_pf_interl_X_mul_both_named) + "rr_pf_interl_X_mul_both" " using " "interl" ":=" term : + tactic + +syntax (name := rr_pf_interl_X_mul_both_compat_named) "rr_pf_interl_X_mul_both" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," "interl" ":=" term : tactic -/-- Sequence form of `rr_pf_interl_X_mul_both`: the same certificate for every index `i : Nat`. -/ +/-- Sequence form of `rr_pf_interl_X_mul_both`: the same interlacing certificate +for every index `i : Nat`. The former PF-certificate fields remain accepted. -/ syntax (name := rr_pf_sequence_interl_X_mul_both_named) + "rr_pf_sequence_interl_X_mul_both" " using " "interl" ":=" term : + tactic + +syntax (name := rr_pf_sequence_interl_X_mul_both_compat_named) "rr_pf_sequence_interl_X_mul_both" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," @@ -575,20 +581,22 @@ macro_rules `(tactic| exact RealRooted.IsPFPolynomial.interl_self $hp) | `(tactic| rr_pf_sequence_interl_self using pf := $hp:term) => `(tactic| exact RealRooted.Tactic.pf_sequence_interl_self $hp) + | `(tactic| rr_pf_interl_X_mul_both using interl := $hpq:term) => + `(tactic| exact RealRooted.Interl.mul_X_both $hpq) | `(tactic| rr_pf_interl_X_mul_both using - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, interl := $hpq:term) => - `(tactic| exact RealRooted.interl_X_mul_both_of_pf $hp $hq $hpq) + `(tactic| exact RealRooted.Interl.mul_X_both $hpq) + | `(tactic| rr_pf_sequence_interl_X_mul_both using interl := $hpq:term) => + `(tactic| exact RealRooted.Tactic.interl_sequence_mul_X_both $hpq) | `(tactic| rr_pf_sequence_interl_X_mul_both using - left_pf := $hp:term, - right_pf := $hq:term, + left_pf := $_hp:term, + right_pf := $_hq:term, interl := $hpq:term) => - `(tactic| - exact RealRooted.Tactic.pf_sequence_interl_X_mul_both - $hp $hq $hpq) + `(tactic| exact RealRooted.Tactic.interl_sequence_mul_X_both $hpq) end Tactic end RealRooted diff --git a/RealRooted/Tactic/WagnerX/Frontend.lean b/RealRooted/Tactic/WagnerX/Frontend.lean index 7b562f9a2..c2f42f1dd 100644 --- a/RealRooted/Tactic/WagnerX/Frontend.lean +++ b/RealRooted/Tactic/WagnerX/Frontend.lean @@ -25,6 +25,10 @@ macro_rules case h => rr_lookup [rr_base_strict_interl] case hfnn => rr_lookup [rr_nonneg] case hgnn => rr_lookup [rr_nonneg])) + | `(tactic| + rr_strict_interl_mul_X_both using proper := $hstrictInterl:term) => + `(tactic| + simpa using RealRooted.StrictInterl.mul_X_sub_C_both $hstrictInterl 0) | `(tactic| rr_strict_interl_mul_X_both using proper := $hstrictInterl:term, @@ -75,21 +79,25 @@ macro_rules case hfnn => rr_lookup [rr_nonneg] case hgnn => rr_lookup [rr_nonneg] case hc => exact ($hc).ne')) + | `(tactic| + rr_strict_interl_X_derivative_X_self using + splits := $hf:term, + degree_two := $hdeg:term) => + `(tactic| + exact RealRooted.strictInterl_X_derivative_X_self_of_splits $hf $hdeg) | `(tactic| rr_strict_interl_X_derivative_X_self using splits := $hf:term, degree_two := $hdeg:term, - nonneg_coeffs := $hfnn:term) => + nonneg_coeffs := $_hfnn:term) => `(tactic| - exact RealRooted.strictInterl_X_derivative_X_self_of_splits_nonneg - $hf $hdeg $hfnn) + exact RealRooted.strictInterl_X_derivative_X_self_of_splits $hf $hdeg) | `(tactic| rr_strict_interl_X_derivative_X_self) => `(tactic| exact (by - apply RealRooted.strictInterl_X_derivative_X_self_of_splits_nonneg + apply RealRooted.strictInterl_X_derivative_X_self_of_splits case hf => rr_lookup - case hdeg => rr_lookup [rr_degree] - case hfnn => rr_lookup [rr_nonneg])) + case hdeg => rr_lookup [rr_degree])) | `(tactic| rr_strict_interl_wagner_derivative_gap_lag using proper := $hstrictInterl:term, diff --git a/RealRooted/Tactic/WagnerX/Syntax.lean b/RealRooted/Tactic/WagnerX/Syntax.lean index b7c393280..9034d4a30 100644 --- a/RealRooted/Tactic/WagnerX/Syntax.lean +++ b/RealRooted/Tactic/WagnerX/Syntax.lean @@ -23,17 +23,21 @@ syntax (name := rr_strict_interl_mul_X) syntax (name := rr_strict_interl_mul_X_inferred) "rr_strict_interl_mul_X" : tactic -/-- Closes `StrictInterl (X * f) (X * g)` from `proper : StrictInterl f g`; -`left_nonneg : HasNonnegCoeffs f`; and `right_nonneg : HasNonnegCoeffs g`. -/ +/-- Closes `StrictInterl (X * f) (X * g)` from `proper : StrictInterl f g`. +The former `left_nonneg` and `right_nonneg` fields remain accepted for compatibility. -/ syntax (name := rr_strict_interl_mul_X_both) + "rr_strict_interl_mul_X_both" " using " "proper" ":=" term : + tactic + +syntax (name := rr_strict_interl_mul_X_both_compat) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term "," "left_nonneg" ":=" term "," "right_nonneg" ":=" term : tactic -/-- Bare form of `rr_strict_interl_mul_X_both`: finds the three certificates in the local context by -`rr_lookup`, using `rr_base_strict_interl` and `rr_nonneg`. -/ +/-- Bare form of `rr_strict_interl_mul_X_both`: finds the strict-interlacing +certificate in the local context using `rr_base_strict_interl`. -/ syntax (name := rr_strict_interl_mul_X_both_inferred) "rr_strict_interl_mul_X_both" : tactic @@ -71,17 +75,24 @@ syntax (name := rr_strict_interl_C_mul_X_pos_inferred) "coeff_pos" ":=" term : tactic -/-- Closes `StrictInterl (X * f.derivative) (X * f)` from `splits : f.Splits`, -`degree_two : 2 ≤ f.natDegree` and `nonneg_coeffs : HasNonnegCoeffs f`. -/ +/-- Closes `StrictInterl (X * f.derivative) (X * f)` from `splits : f.Splits` +and `degree_two : 2 ≤ f.natDegree`. The former `nonneg_coeffs` field remains +accepted for compatibility. -/ syntax (name := rr_strict_interl_X_derivative_X_self) + "rr_strict_interl_X_derivative_X_self" " using " + "splits" ":=" term "," + "degree_two" ":=" term : + tactic + +syntax (name := rr_strict_interl_X_derivative_X_self_compat) "rr_strict_interl_X_derivative_X_self" " using " "splits" ":=" term "," "degree_two" ":=" term "," "nonneg_coeffs" ":=" term : tactic -/-- Bare form of `rr_strict_interl_X_derivative_X_self`: finds the three certificates in the local -context by `rr_lookup`, using `rr_degree` and `rr_nonneg`. -/ +/-- Bare form of `rr_strict_interl_X_derivative_X_self`: finds the splitting +and degree certificates in the local context, using `rr_degree` for the latter. -/ syntax (name := rr_strict_interl_X_derivative_X_self_inferred) "rr_strict_interl_X_derivative_X_self" : tactic diff --git a/RealRooted/WagnerX/ListInterlacing.lean b/RealRooted/WagnerX/ListInterlacing.lean index 47fd2d97e..721098f70 100644 --- a/RealRooted/WagnerX/ListInterlacing.lean +++ b/RealRooted/WagnerX/ListInterlacing.lean @@ -490,4 +490,43 @@ theorem StrictInterl.of_mul_X_sub_C_both {f g : ℝ[X]} {r : ℝ} lia exact Or.inr ⟨hlen', listAlternates_of_orderedInsert r hlen' hss_sorted hrs_sorted halt⟩ +/-- Multiplication by the same affine factor on both sides is an equivalence +on strict interlacing. -/ +theorem StrictInterl.mul_X_sub_C_both_iff {f g : ℝ[X]} (r : ℝ) : + StrictInterl f g ↔ StrictInterl ((X - C r) * f) ((X - C r) * g) := + ⟨fun h => h.mul_X_sub_C_both r, StrictInterl.of_mul_X_sub_C_both⟩ + +/-- Multiplying both polynomials by the same affine factor preserves +zero-aware interlacing. -/ +theorem Interl.mul_X_sub_C_both {f g : ℝ[X]} (h : Interl f g) (r : ℝ) : + Interl ((X - C r) * f) ((X - C r) * g) := by + rcases h with rfl | rfl | hfg + · simpa using interl_zero_left ((X - C r) * g) + · simpa using interl_zero_right ((X - C r) * f) + · exact (hfg.mul_X_sub_C_both r).toInterl + +/-- Cancelling a common affine factor preserves zero-aware interlacing. -/ +theorem Interl.of_mul_X_sub_C_both {f g : ℝ[X]} {r : ℝ} + (h : Interl ((X - C r) * f) ((X - C r) * g)) : + Interl f g := by + by_cases hf0 : f = 0 + · simpa [hf0] using interl_zero_left g + by_cases hg0 : g = 0 + · simpa [hg0] using interl_zero_right f + have hstrict : StrictInterl ((X - C r) * f) ((X - C r) * g) := + h.toStrictInterl_of_ne + (mul_ne_zero (X_sub_C_ne_zero r) hf0) (mul_ne_zero (X_sub_C_ne_zero r) hg0) + exact hstrict.of_mul_X_sub_C_both.toInterl + +/-- Multiplying both polynomials by `X` preserves zero-aware interlacing. -/ +theorem Interl.mul_X_both {f g : ℝ[X]} (h : Interl f g) : + Interl (X * f) (X * g) := by + simpa using h.mul_X_sub_C_both 0 + +/-- Cancelling a common factor `X` preserves zero-aware interlacing. -/ +theorem Interl.of_mul_X_both {f g : ℝ[X]} (h : Interl (X * f) (X * g)) : + Interl f g := by + apply Interl.of_mul_X_sub_C_both (r := 0) + simpa using h + end RealRooted diff --git a/RealRooted/WagnerX/NonnegativeRoots.lean b/RealRooted/WagnerX/NonnegativeRoots.lean index 2f583a95c..f30c9390a 100644 --- a/RealRooted/WagnerX/NonnegativeRoots.lean +++ b/RealRooted/WagnerX/NonnegativeRoots.lean @@ -333,40 +333,19 @@ theorem StrictInterl.mul_X_both_of_nonneg {f g : ℝ[X]} /-- Multiplication by `X` on both sides is an equivalence on strict interlacing when all roots are nonpositive. -/ -@[deprecated StrictInterl.mul_X_sub_C_both +typeChanged (since := "2026-10-21")] +@[deprecated StrictInterl.mul_X_sub_C_both_iff +typeChanged (since := "2026-10-21")] theorem StrictInterl.mul_X_both_iff_of_roots_nonpos {f g : ℝ[X]} (_hf_nonpos : ∀ r ∈ f.roots, r ≤ 0) (_hg_nonpos : ∀ r ∈ g.roots, r ≤ 0) : - StrictInterl f g ↔ StrictInterl (X * f) (X * g) := - ⟨fun h => by simpa using h.mul_X_sub_C_both 0, - fun h => by - apply StrictInterl.of_mul_X_sub_C_both (r := 0) - simpa using h⟩ - -/-- Multiplying both polynomials by `X` preserves zero-aware interlacing for -polynomials with nonnegative coefficients. -/ + StrictInterl f g ↔ StrictInterl (X * f) (X * g) := by + simpa using StrictInterl.mul_X_sub_C_both_iff (f := f) (g := g) 0 + +/-- Compatibility form of common-`X` multiplication for zero-aware +interlacing. -/ +@[deprecated Interl.mul_X_both +typeChanged (since := "2026-10-21")] theorem Interl.mul_X_both_of_nonneg {f g : ℝ[X]} - (h : Interl f g) (hfnn : HasNonnegCoeffs f) (hgnn : HasNonnegCoeffs g) : + (h : Interl f g) (_hfnn : HasNonnegCoeffs f) (_hgnn : HasNonnegCoeffs g) : Interl (X * f) (X * g) := by - rcases h with rfl | rfl | hfg - · simpa using interl_zero_left (X * g) - · simpa using interl_zero_right (X * f) - · exact (by simpa using hfg.mul_X_sub_C_both 0 : StrictInterl (X * f) (X * g)).toInterl - -/-- Cancelling a common factor `X` preserves zero-aware interlacing for -polynomials with nonnegative coefficients. -/ -theorem Interl.of_mul_X_both_of_nonneg {f g : ℝ[X]} - (h : Interl (X * f) (X * g)) (_hfnn : HasNonnegCoeffs f) - (_hgnn : HasNonnegCoeffs g) : - Interl f g := by - by_cases hf0 : f = 0 - · simpa [hf0] using interl_zero_left g - by_cases hg0 : g = 0 - · simpa [hg0] using interl_zero_right f - have hstrict : StrictInterl (X * f) (X * g) := - h.toStrictInterl_of_ne (mul_ne_zero X_ne_zero hf0) (mul_ne_zero X_ne_zero hg0) - apply StrictInterl.toInterl - apply StrictInterl.of_mul_X_sub_C_both (r := 0) - simpa using hstrict + exact h.mul_X_both end RealRooted diff --git a/RealRooted/WagnerX/ProperPosition.lean b/RealRooted/WagnerX/ProperPosition.lean index d50e80c47..95db43cf2 100644 --- a/RealRooted/WagnerX/ProperPosition.lean +++ b/RealRooted/WagnerX/ProperPosition.lean @@ -5,20 +5,28 @@ import RealRooted.WagnerX # Wagner `X`-multiplication interlacing bridges The forward and reverse interlacing transports associated with multiplying -a nonnegative-coefficient polynomial by `X`. +a polynomial by `X`. -/ open Polynomial namespace RealRooted -/-- The derivative of a split nonnegative-coefficient polynomial preserves the -Wagner `X`-multiplication interlacing relation. -/ -theorem strictInterl_X_derivative_X_self_of_splits_nonneg {f : ℝ[X]} - (hf : f.Splits) (hdeg : 2 ≤ f.natDegree) (_hfnn : HasNonnegCoeffs f) : +/-- The derivative of a split polynomial preserves the common-`X` +strict-interlacing relation in degree at least two. -/ +theorem strictInterl_X_derivative_X_self_of_splits {f : ℝ[X]} + (hf : f.Splits) (hdeg : 2 ≤ f.natDegree) : StrictInterl (X * f.derivative) (X * f) := by have hder : StrictInterl f.derivative f := (derivative_interlaces_of_natDegree_ne_zero hf (by lia)).toStrictInterl simpa using hder.mul_X_sub_C_both 0 +/-- Compatibility form retaining the former nonnegative-coefficient +hypothesis. -/ +@[deprecated strictInterl_X_derivative_X_self_of_splits +typeChanged (since := "2026-10-21")] +theorem strictInterl_X_derivative_X_self_of_splits_nonneg {f : ℝ[X]} + (hf : f.Splits) (hdeg : 2 ≤ f.natDegree) (_hfnn : HasNonnegCoeffs f) : + StrictInterl (X * f.derivative) (X * f) := + strictInterl_X_derivative_X_self_of_splits hf hdeg + end RealRooted From 1fbc53e838016a8b1d1f41fcb9aedee7205820ca Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 17:00:19 +0000 Subject: [PATCH 3/6] Document compatibility tactic forms; regenerate OEIS tactic coverage Co-Authored-By: Claude Opus 5.5 --- RealRooted/Tactic/EulerOperator.lean | 8 ++++++++ RealRooted/Tactic/OEIS_COVERAGE.md | 4 ++-- RealRooted/Tactic/PFPolynomial.lean | 4 ++++ RealRooted/Tactic/WagnerX/Syntax.lean | 4 ++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/RealRooted/Tactic/EulerOperator.lean b/RealRooted/Tactic/EulerOperator.lean index 87a70864c..b4cc8364f 100644 --- a/RealRooted/Tactic/EulerOperator.lean +++ b/RealRooted/Tactic/EulerOperator.lean @@ -210,6 +210,8 @@ syntax (name := rr_thetaPlusOne_interl_named) "rr_thetaPlusOne_interl" " using " "interl" ":=" term : tactic +/-- Compatibility form of `rr_thetaPlusOne_interl`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_thetaPlusOne_interl_compat_named) "rr_thetaPlusOne_interl" " using " "left_pf" ":=" term "," @@ -223,6 +225,8 @@ syntax (name := rr_thetaPlusOne_sequence_interl_named) "rr_thetaPlusOne_sequence_interl" " using " "interl" ":=" term : tactic +/-- Compatibility form of `rr_thetaPlusOne_sequence_interl`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_thetaPlusOne_sequence_interl_compat_named) "rr_thetaPlusOne_sequence_interl" " using " "left_pf" ":=" term "," @@ -238,6 +242,8 @@ syntax (name := rr_iterateThetaPlusOne_interl_named) "interl" ":=" term : tactic +/-- Compatibility form of `rr_iterateThetaPlusOne_interl`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_iterateThetaPlusOne_interl_compat_named) "rr_iterateThetaPlusOne_interl" " using " "index" ":=" term "," @@ -254,6 +260,8 @@ syntax (name := rr_iterateThetaPlusOne_sequence_interl_named) "interl" ":=" term : tactic +/-- Compatibility form of `rr_iterateThetaPlusOne_sequence_interl`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_iterateThetaPlusOne_sequence_interl_compat_named) "rr_iterateThetaPlusOne_sequence_interl" " using " "index" ":=" term "," diff --git a/RealRooted/Tactic/OEIS_COVERAGE.md b/RealRooted/Tactic/OEIS_COVERAGE.md index 839c50024..24f9757d6 100644 --- a/RealRooted/Tactic/OEIS_COVERAGE.md +++ b/RealRooted/Tactic/OEIS_COVERAGE.md @@ -166,7 +166,7 @@ Current totals: **308 IDs**; **34 formalized**, **261 shells**, **3 fragments**, | A122848 | `shell` | OEIS shapes `/`: `P_n = (1+t)P_{n-1}+c_n t P_{n-2}`.
after reindexing, `P_{n+2}=tP_{n+1}+n t P_n`.
+1 additional test intents | `rr_lw_current_X_sequence`, `rr_lw_current_X_sequence_auto`, `rr_lw_positive_t` | `base`, `coeff_nonneg`, `degree_lower`, `degree_succ`, `degree_upper`, `interlacer`, `interlacer_pos_lc`, `no_common_roots`, `nonneg_coeffs`, `pos_lc`, `recurrence`, `roots_nonpos`, `target_pos_lc` | concrete row definition and proofs of the listed certificates | | A124038 | `shell` | OEIS shape `/`: `P_{n+2}=tP_{n+1}-P_n`.
OEIS shapes `//`: real-rootedness consequence of
+1 additional test intents | `rr_favard_const`, `rr_favard_const_unit` | `alpha`, `base_one`, `base_zero`, `step` | concrete row definition and proofs of the listed certificates | | A124039 | `shell` | row-sign normalized Chebyshev step `P_{n+2}=-tP_{n+1}-P_n`.
real-rootedness endpoint for the same row-sign normalization.
+1 additional test intents | `rr_favard_const_row_sign_unit`, `rr_favard_param_row_sign_unit` | `alpha`, `base_one`, `base_zero`, `step` | concrete row definition and proofs of the listed certificates | -| A124324 | `shell` | Active-offset `/` shape: | `rr_nonneg_coeffs`, `rr_strict_interl_mul_X_both`, `rr_strict_interl_wagner_derivative_gap_lag_sequence`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_realrooted`, `rr_wagner_pos_seq` | `base`, `degree_two`, `derivative_coeff_pos`, `lag_coeff_pos`, `left_nonneg`, `natDegree`, `nonneg_coeffs`, `proper`, `recurrence`, `right_nonneg` | concrete row definition and proofs of the listed certificates | +| A124324 | `shell` | Active-offset `/` shape: | `rr_nonneg_coeffs`, `rr_strict_interl_mul_X_both`, `rr_strict_interl_wagner_derivative_gap_lag_sequence`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_realrooted`, `rr_wagner_pos_seq` | `base`, `degree_two`, `derivative_coeff_pos`, `lag_coeff_pos`, `natDegree`, `nonneg_coeffs`, `proper`, `recurrence` | concrete row definition and proofs of the listed certificates | | A124376 | `shell` | residual (): the rows are `(1 + X) ^ m` times `X⁴ + b X³ + c X² + b X + 1`.
def : ℕ → ℝ[X]
+4 additional test intents | `rr_row_splits` | implicit/local certificates resolved by the route | concrete row definition and proofs of the listed certificates | | A124848 | `formalized` | This is the denominator bookkeeping needed for `/`-style | `rr_lw_coeff_nonneg_seq_term`, `rr_lw_neg_C_mul_one_add_X_lag_sequence_den_coeff_nonneg` | `base`, `coeff`, `coeff_nonneg`, `degree_succ`, `no_common_roots`, `nonneg_coeffs`, `pos_lc`, `raw_recurrence`, `root_lower` | none | | A124860 | `shell` | the numeric probe finds the factors and their exponents ().
def : ℕ → ℝ[X]
+2 additional test intents | `rr_row_splits` | implicit/local certificates resolved by the route | concrete row definition and proofs of the listed certificates | @@ -315,7 +315,7 @@ Current totals: **308 IDs**; **34 formalized**, **261 shells**, **3 fragments**, | A341287 | `fragment` | `v_n(t)=t-1`. | `rr_sign_at_roots_upper` | root sign/interval hypotheses | full recurrence shell, base cases, degree, and leading-coefficient data | | A347056 | `shell` | This is the denominator bookkeeping needed for `/`-style | `rr_lw_coeff_nonneg_seq_term`, `rr_lw_neg_C_mul_one_add_X_lag_sequence_den_coeff_nonneg` | `base`, `coeff`, `coeff_nonneg`, `degree_succ`, `no_common_roots`, `nonneg_coeffs`, `pos_lc`, `raw_recurrence`, `root_lower` | concrete row definition and proofs of the listed certificates | | A357613 | `shell` | namespace Downstream
The exact downstream recurrence presentation of .
+17 additional test intents | `rr_mw_active_den_at_term`, `rr_mw_den_norm`, `rr_row_interlaces`, `rr_row_natDegree` | `den_nonzero`, `n`, `recurrence`, `via` | concrete row definition and proofs of the listed certificates | -| A358623 | `shell` | -style Wagner gap-lag branch, adjacent-`StrictInterl` endpoint.
-style Wagner gap-lag branch, real-rootedness endpoint.
+8 additional test intents | `rr_i2_derivative_lag_sequence`, `rr_i2_derivative_lag_sequence_realrooted`, `rr_nonneg_coeffs`, `rr_strict_interl_mul_X_both`, `rr_strict_interl_wagner_derivative_gap_lag_sequence`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_den`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_realrooted`, `rr_wagner_pos_seq` | `base`, `degree_two`, `denom_pos`, `derivative_coeff_pos`, `lag_coeff_pos`, `left_nonneg`, `natDegree`, `nonneg_coeffs`, `proper`, `recurrence`, `right_nonneg` | concrete row definition and proofs of the listed certificates | +| A358623 | `shell` | -style Wagner gap-lag branch, adjacent-`StrictInterl` endpoint.
-style Wagner gap-lag branch, real-rootedness endpoint.
+8 additional test intents | `rr_i2_derivative_lag_sequence`, `rr_i2_derivative_lag_sequence_realrooted`, `rr_nonneg_coeffs`, `rr_strict_interl_mul_X_both`, `rr_strict_interl_wagner_derivative_gap_lag_sequence`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_den`, `rr_strict_interl_wagner_derivative_gap_lag_sequence_realrooted`, `rr_wagner_pos_seq` | `base`, `degree_two`, `denom_pos`, `derivative_coeff_pos`, `lag_coeff_pos`, `natDegree`, `nonneg_coeffs`, `proper`, `recurrence` | concrete row definition and proofs of the listed certificates | | A359363 | `formalized` | import RealRooted.Applications.OEIS.
The downstream literal recurrence presentation of .
+9 additional test intents | `rr_row_interlaces`, `rr_row_natDegree`, `rr_row_splits` | `n` | none | | A361893 | `shell` | split scalar denominator normalizing into `-c_n t^2 P'`. | `rr_mw_active_den_at`, `rr_mw_coeff_at`, `rr_mw_den_norm_coeff`, `rr_mw_derivative_neg_X_sq_sequence_auto` | `base`, `coeff_eq`, `degree_succ`, `den_nonzero`, `derivative`, `pos_lc`, `recurrence` | concrete row definition and proofs of the listed certificates | | A366159 | `shell` | The downstream recurrence used to regress the remaining degree route.
def : ℕ → ℝ[X]
+6 additional test intents | `rr_row_natDegree` | `via` | concrete row definition and proofs of the listed certificates | diff --git a/RealRooted/Tactic/PFPolynomial.lean b/RealRooted/Tactic/PFPolynomial.lean index 775ccf0fb..54f162988 100644 --- a/RealRooted/Tactic/PFPolynomial.lean +++ b/RealRooted/Tactic/PFPolynomial.lean @@ -417,6 +417,8 @@ syntax (name := rr_pf_interl_X_mul_both_named) "rr_pf_interl_X_mul_both" " using " "interl" ":=" term : tactic +/-- Compatibility form of `rr_pf_interl_X_mul_both`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_pf_interl_X_mul_both_compat_named) "rr_pf_interl_X_mul_both" " using " "left_pf" ":=" term "," @@ -430,6 +432,8 @@ syntax (name := rr_pf_sequence_interl_X_mul_both_named) "rr_pf_sequence_interl_X_mul_both" " using " "interl" ":=" term : tactic +/-- Compatibility form of `rr_pf_sequence_interl_X_mul_both`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_pf_sequence_interl_X_mul_both_compat_named) "rr_pf_sequence_interl_X_mul_both" " using " "left_pf" ":=" term "," diff --git a/RealRooted/Tactic/WagnerX/Syntax.lean b/RealRooted/Tactic/WagnerX/Syntax.lean index 9034d4a30..c242cfe02 100644 --- a/RealRooted/Tactic/WagnerX/Syntax.lean +++ b/RealRooted/Tactic/WagnerX/Syntax.lean @@ -29,6 +29,8 @@ syntax (name := rr_strict_interl_mul_X_both) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term : tactic +/-- Compatibility form of `rr_strict_interl_mul_X_both`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_strict_interl_mul_X_both_compat) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term "," @@ -84,6 +86,8 @@ syntax (name := rr_strict_interl_X_derivative_X_self) "degree_two" ":=" term : tactic +/-- Compatibility form of `rr_strict_interl_X_derivative_X_self`: the former extra certificate fields are accepted +and ignored, since the conclusion no longer needs them. -/ syntax (name := rr_strict_interl_X_derivative_X_self_compat) "rr_strict_interl_X_derivative_X_self" " using " "splits" ":=" term "," From c1ddba603bb1b5b7dd49dd3b7b9542953ce069ca Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 17:03:00 +0000 Subject: [PATCH 4/6] Wrap compatibility tactic docstrings Co-Authored-By: Claude Opus 5.5 --- RealRooted/Tactic/EulerOperator.lean | 20 ++++++++++++-------- RealRooted/Tactic/PFPolynomial.lean | 10 ++++++---- RealRooted/Tactic/WagnerX/Syntax.lean | 10 ++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/RealRooted/Tactic/EulerOperator.lean b/RealRooted/Tactic/EulerOperator.lean index b4cc8364f..473bb50a0 100644 --- a/RealRooted/Tactic/EulerOperator.lean +++ b/RealRooted/Tactic/EulerOperator.lean @@ -210,8 +210,9 @@ syntax (name := rr_thetaPlusOne_interl_named) "rr_thetaPlusOne_interl" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_thetaPlusOne_interl`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_thetaPlusOne_interl`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_thetaPlusOne_interl_compat_named) "rr_thetaPlusOne_interl" " using " "left_pf" ":=" term "," @@ -225,8 +226,9 @@ syntax (name := rr_thetaPlusOne_sequence_interl_named) "rr_thetaPlusOne_sequence_interl" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_thetaPlusOne_sequence_interl`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_thetaPlusOne_sequence_interl`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_thetaPlusOne_sequence_interl_compat_named) "rr_thetaPlusOne_sequence_interl" " using " "left_pf" ":=" term "," @@ -242,8 +244,9 @@ syntax (name := rr_iterateThetaPlusOne_interl_named) "interl" ":=" term : tactic -/-- Compatibility form of `rr_iterateThetaPlusOne_interl`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_iterateThetaPlusOne_interl`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_iterateThetaPlusOne_interl_compat_named) "rr_iterateThetaPlusOne_interl" " using " "index" ":=" term "," @@ -260,8 +263,9 @@ syntax (name := rr_iterateThetaPlusOne_sequence_interl_named) "interl" ":=" term : tactic -/-- Compatibility form of `rr_iterateThetaPlusOne_sequence_interl`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_iterateThetaPlusOne_sequence_interl`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_iterateThetaPlusOne_sequence_interl_compat_named) "rr_iterateThetaPlusOne_sequence_interl" " using " "index" ":=" term "," diff --git a/RealRooted/Tactic/PFPolynomial.lean b/RealRooted/Tactic/PFPolynomial.lean index 54f162988..2a935f3d5 100644 --- a/RealRooted/Tactic/PFPolynomial.lean +++ b/RealRooted/Tactic/PFPolynomial.lean @@ -417,8 +417,9 @@ syntax (name := rr_pf_interl_X_mul_both_named) "rr_pf_interl_X_mul_both" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_pf_interl_X_mul_both`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_pf_interl_X_mul_both`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_pf_interl_X_mul_both_compat_named) "rr_pf_interl_X_mul_both" " using " "left_pf" ":=" term "," @@ -432,8 +433,9 @@ syntax (name := rr_pf_sequence_interl_X_mul_both_named) "rr_pf_sequence_interl_X_mul_both" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_pf_sequence_interl_X_mul_both`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_pf_sequence_interl_X_mul_both`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_pf_sequence_interl_X_mul_both_compat_named) "rr_pf_sequence_interl_X_mul_both" " using " "left_pf" ":=" term "," diff --git a/RealRooted/Tactic/WagnerX/Syntax.lean b/RealRooted/Tactic/WagnerX/Syntax.lean index c242cfe02..41f6135d1 100644 --- a/RealRooted/Tactic/WagnerX/Syntax.lean +++ b/RealRooted/Tactic/WagnerX/Syntax.lean @@ -29,8 +29,9 @@ syntax (name := rr_strict_interl_mul_X_both) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term : tactic -/-- Compatibility form of `rr_strict_interl_mul_X_both`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_strict_interl_mul_X_both`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_strict_interl_mul_X_both_compat) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term "," @@ -86,8 +87,9 @@ syntax (name := rr_strict_interl_X_derivative_X_self) "degree_two" ":=" term : tactic -/-- Compatibility form of `rr_strict_interl_X_derivative_X_self`: the former extra certificate fields are accepted -and ignored, since the conclusion no longer needs them. -/ +/-- Compatibility form of `rr_strict_interl_X_derivative_X_self`: +the former extra certificate fields are accepted and ignored, +since the conclusion no longer needs them. -/ syntax (name := rr_strict_interl_X_derivative_X_self_compat) "rr_strict_interl_X_derivative_X_self" " using " "splits" ":=" term "," From 18350dc82b2f2123fc7055707a8acf17cbc0314d Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 17:12:41 +0000 Subject: [PATCH 5/6] Mark compatibility tactic forms as tactic_alt Co-Authored-By: Claude Opus 5.5 --- RealRooted/Tactic/EulerOperator.lean | 16 ++++------------ RealRooted/Tactic/PFPolynomial.lean | 8 ++------ RealRooted/Tactic/WagnerX/Syntax.lean | 8 ++------ 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/RealRooted/Tactic/EulerOperator.lean b/RealRooted/Tactic/EulerOperator.lean index 473bb50a0..65a9cdef5 100644 --- a/RealRooted/Tactic/EulerOperator.lean +++ b/RealRooted/Tactic/EulerOperator.lean @@ -210,9 +210,7 @@ syntax (name := rr_thetaPlusOne_interl_named) "rr_thetaPlusOne_interl" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_thetaPlusOne_interl`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_thetaPlusOne_interl_named] syntax (name := rr_thetaPlusOne_interl_compat_named) "rr_thetaPlusOne_interl" " using " "left_pf" ":=" term "," @@ -226,9 +224,7 @@ syntax (name := rr_thetaPlusOne_sequence_interl_named) "rr_thetaPlusOne_sequence_interl" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_thetaPlusOne_sequence_interl`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_thetaPlusOne_sequence_interl_named] syntax (name := rr_thetaPlusOne_sequence_interl_compat_named) "rr_thetaPlusOne_sequence_interl" " using " "left_pf" ":=" term "," @@ -244,9 +240,7 @@ syntax (name := rr_iterateThetaPlusOne_interl_named) "interl" ":=" term : tactic -/-- Compatibility form of `rr_iterateThetaPlusOne_interl`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_iterateThetaPlusOne_interl_named] syntax (name := rr_iterateThetaPlusOne_interl_compat_named) "rr_iterateThetaPlusOne_interl" " using " "index" ":=" term "," @@ -263,9 +257,7 @@ syntax (name := rr_iterateThetaPlusOne_sequence_interl_named) "interl" ":=" term : tactic -/-- Compatibility form of `rr_iterateThetaPlusOne_sequence_interl`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_iterateThetaPlusOne_sequence_interl_named] syntax (name := rr_iterateThetaPlusOne_sequence_interl_compat_named) "rr_iterateThetaPlusOne_sequence_interl" " using " "index" ":=" term "," diff --git a/RealRooted/Tactic/PFPolynomial.lean b/RealRooted/Tactic/PFPolynomial.lean index 2a935f3d5..92e18d241 100644 --- a/RealRooted/Tactic/PFPolynomial.lean +++ b/RealRooted/Tactic/PFPolynomial.lean @@ -417,9 +417,7 @@ syntax (name := rr_pf_interl_X_mul_both_named) "rr_pf_interl_X_mul_both" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_pf_interl_X_mul_both`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_pf_interl_X_mul_both_named] syntax (name := rr_pf_interl_X_mul_both_compat_named) "rr_pf_interl_X_mul_both" " using " "left_pf" ":=" term "," @@ -433,9 +431,7 @@ syntax (name := rr_pf_sequence_interl_X_mul_both_named) "rr_pf_sequence_interl_X_mul_both" " using " "interl" ":=" term : tactic -/-- Compatibility form of `rr_pf_sequence_interl_X_mul_both`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_pf_sequence_interl_X_mul_both_named] syntax (name := rr_pf_sequence_interl_X_mul_both_compat_named) "rr_pf_sequence_interl_X_mul_both" " using " "left_pf" ":=" term "," diff --git a/RealRooted/Tactic/WagnerX/Syntax.lean b/RealRooted/Tactic/WagnerX/Syntax.lean index 41f6135d1..de4a121cb 100644 --- a/RealRooted/Tactic/WagnerX/Syntax.lean +++ b/RealRooted/Tactic/WagnerX/Syntax.lean @@ -29,9 +29,7 @@ syntax (name := rr_strict_interl_mul_X_both) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term : tactic -/-- Compatibility form of `rr_strict_interl_mul_X_both`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_strict_interl_mul_X_both] syntax (name := rr_strict_interl_mul_X_both_compat) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term "," @@ -87,9 +85,7 @@ syntax (name := rr_strict_interl_X_derivative_X_self) "degree_two" ":=" term : tactic -/-- Compatibility form of `rr_strict_interl_X_derivative_X_self`: -the former extra certificate fields are accepted and ignored, -since the conclusion no longer needs them. -/ +@[tactic_alt rr_strict_interl_X_derivative_X_self] syntax (name := rr_strict_interl_X_derivative_X_self_compat) "rr_strict_interl_X_derivative_X_self" " using " "splits" ":=" term "," From 7a178a5656ed6293719df70a062d2099793704c4 Mon Sep 17 00:00:00 2001 From: Per Alexandersson Date: Wed, 21 Oct 2026 17:28:30 +0000 Subject: [PATCH 6/6] Name compatibility tactic syntaxes in lowerCamelCase Co-Authored-By: Claude Opus 5.5 --- RealRooted/Tactic/EulerOperator.lean | 8 ++++---- RealRooted/Tactic/PFPolynomial.lean | 4 ++-- RealRooted/Tactic/WagnerX/Syntax.lean | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/RealRooted/Tactic/EulerOperator.lean b/RealRooted/Tactic/EulerOperator.lean index 65a9cdef5..044fbee8c 100644 --- a/RealRooted/Tactic/EulerOperator.lean +++ b/RealRooted/Tactic/EulerOperator.lean @@ -211,7 +211,7 @@ syntax (name := rr_thetaPlusOne_interl_named) tactic @[tactic_alt rr_thetaPlusOne_interl_named] -syntax (name := rr_thetaPlusOne_interl_compat_named) +syntax (name := rrThetaPlusOneInterlCompat) "rr_thetaPlusOne_interl" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," @@ -225,7 +225,7 @@ syntax (name := rr_thetaPlusOne_sequence_interl_named) tactic @[tactic_alt rr_thetaPlusOne_sequence_interl_named] -syntax (name := rr_thetaPlusOne_sequence_interl_compat_named) +syntax (name := rrThetaPlusOneSequenceInterlCompat) "rr_thetaPlusOne_sequence_interl" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," @@ -241,7 +241,7 @@ syntax (name := rr_iterateThetaPlusOne_interl_named) tactic @[tactic_alt rr_iterateThetaPlusOne_interl_named] -syntax (name := rr_iterateThetaPlusOne_interl_compat_named) +syntax (name := rrIterateThetaPlusOneInterlCompat) "rr_iterateThetaPlusOne_interl" " using " "index" ":=" term "," "left_pf" ":=" term "," @@ -258,7 +258,7 @@ syntax (name := rr_iterateThetaPlusOne_sequence_interl_named) tactic @[tactic_alt rr_iterateThetaPlusOne_sequence_interl_named] -syntax (name := rr_iterateThetaPlusOne_sequence_interl_compat_named) +syntax (name := rrIterateThetaPlusOneSequenceInterlCompat) "rr_iterateThetaPlusOne_sequence_interl" " using " "index" ":=" term "," "left_pf" ":=" term "," diff --git a/RealRooted/Tactic/PFPolynomial.lean b/RealRooted/Tactic/PFPolynomial.lean index 92e18d241..f96062dc6 100644 --- a/RealRooted/Tactic/PFPolynomial.lean +++ b/RealRooted/Tactic/PFPolynomial.lean @@ -418,7 +418,7 @@ syntax (name := rr_pf_interl_X_mul_both_named) tactic @[tactic_alt rr_pf_interl_X_mul_both_named] -syntax (name := rr_pf_interl_X_mul_both_compat_named) +syntax (name := rrPfInterlXMulBothCompat) "rr_pf_interl_X_mul_both" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," @@ -432,7 +432,7 @@ syntax (name := rr_pf_sequence_interl_X_mul_both_named) tactic @[tactic_alt rr_pf_sequence_interl_X_mul_both_named] -syntax (name := rr_pf_sequence_interl_X_mul_both_compat_named) +syntax (name := rrPfSequenceInterlXMulBothCompat) "rr_pf_sequence_interl_X_mul_both" " using " "left_pf" ":=" term "," "right_pf" ":=" term "," diff --git a/RealRooted/Tactic/WagnerX/Syntax.lean b/RealRooted/Tactic/WagnerX/Syntax.lean index de4a121cb..511c47332 100644 --- a/RealRooted/Tactic/WagnerX/Syntax.lean +++ b/RealRooted/Tactic/WagnerX/Syntax.lean @@ -30,7 +30,7 @@ syntax (name := rr_strict_interl_mul_X_both) tactic @[tactic_alt rr_strict_interl_mul_X_both] -syntax (name := rr_strict_interl_mul_X_both_compat) +syntax (name := rrStrictInterlMulXBothCompat) "rr_strict_interl_mul_X_both" " using " "proper" ":=" term "," "left_nonneg" ":=" term "," @@ -86,7 +86,7 @@ syntax (name := rr_strict_interl_X_derivative_X_self) tactic @[tactic_alt rr_strict_interl_X_derivative_X_self] -syntax (name := rr_strict_interl_X_derivative_X_self_compat) +syntax (name := rrStrictInterlXDerivativeXSelfCompat) "rr_strict_interl_X_derivative_X_self" " using " "splits" ":=" term "," "degree_two" ":=" term ","