Count the sign changes of a real list: the number of adjacent pairs
whose product is negative. Callers first drop the zero entries (see
Sturm.signVariations), so on a zero-free list this is exactly the number
of adjacent opposite-sign pairs.
Equations
- Sturm.countSignChanges (a :: b :: rest) = (if a * b < 0 then 1 else 0) + Sturm.countSignChanges (b :: rest)
- Sturm.countSignChanges x✝ = 0
Instances For
Zero-skipping sign variations of a real list: drop the zeros, then count
the adjacent opposite-sign pairs. This is the variation count that both the
pointwise chain evaluations and the leading-coefficient signs at ±∞ feed
into.
Equations
- Sturm.signVariations l = Sturm.countSignChanges (List.filter (fun (v : ℝ) => decide (v ≠ 0)) l)
Instances For
Prepending a zero entry does not change the sign variations.
A nonzero first entry survives removal of zero entries.
Zero-skipping sign variations of the chain chain evaluated at x:
the sign variations of the list of evaluations chain.map (·.eval x).
Equations
- Sturm.sturmVar chain x = Sturm.signVariations (List.map (Polynomial.eval x) chain)
Instances For
A chain element that vanishes at x contributes no variation at x:
sturmVar ignores it.
Two real lists whose entries have pointwise equal signs have equal
countSignChanges: the sign-change count reads only the signs of the entries.
signVariations reads only the signs of the entries: two real lists whose
entries are pointwise sign-equal have equal sign variations.
The sign of the first nonzero entry of a real list, or 0 if every entry is zero.
Equations
- Sturm.firstSign l = (Option.map (⇑SignType.sign) (List.filter (fun (v : ℝ) => decide (v ≠ 0)) l).head?).getD 0
Instances For
Prepending a nonzero entry a adds one variation exactly when its sign is
opposite the sign of the next surviving entry.
Sign variations of the chain at +∞: the sign of each element there is the
sign of its leading coefficient, so this is the zero-skipping variation count
of the leading coefficients. The zero polynomial contributes leading
coefficient 0, which the zero-skipping convention drops.
Equations
- Sturm.sturmVarPosInf chain = Sturm.signVariations (List.map Polynomial.leadingCoeff chain)
Instances For
Sign variations of the chain at −∞: the sign of an element there is the
sign of its leading coefficient times (-1) ^ degree, so this is the
zero-skipping variation count of leadingCoeff · (-1) ^ natDegree.
Equations
- Sturm.sturmVarNegInf chain = Sturm.signVariations (List.map (fun (q : Polynomial ℝ) => q.leadingCoeff * (-1) ^ q.natDegree) chain)
Instances For
A generalized Sturm chain for a real polynomial.
At a root of the first polynomial, the product of the first two entries changes from negative to positive. At a root of an interior entry, its neighbors have opposite signs. The last entry has no real roots, and every entry is nonzero.
These conditions allow the one-element chain of a nonzero constant polynomial.
The head of the chain is
p.- root_flank (r : ℝ) : p.IsRoot r → ∃ (q : Polynomial ℝ), chain[1]? = some q ∧ Polynomial.eval r q ≠ 0 ∧ (∀ᶠ (x : ℝ) in nhdsWithin r (Set.Iio r), Polynomial.eval x (p * q) < 0) ∧ ∀ᶠ (x : ℝ) in nhdsWithin r (Set.Ioi r), 0 < Polynomial.eval x (p * q)
At every real root
rofp, the chain has a second elementq, nonzero atr, withp * qnegative just left ofrand positive just right ofr. - nonzero_mem (q : Polynomial ℝ) : q ∈ chain → q ≠ 0
No chain element is the zero polynomial.
- interior_alternates (i : ℕ) (x : ℝ) (a b c : Polynomial ℝ) : chain[i]? = some a → chain[i + 1]? = some b → chain[i + 2]? = some c → Polynomial.eval x b = 0 → Polynomial.eval x a ≠ 0 ∧ Polynomial.eval x c ≠ 0 ∧ Polynomial.eval x a * Polynomial.eval x c < 0
Whenever the interior element
b = chain[i+1]vanishes atx, its two neighboursa = chain[i]andc = chain[i+2]are nonzero there and have opposite signs. - last_no_root (q : Polynomial ℝ) : chain.getLast? = some q → ∀ (x : ℝ), Polynomial.eval x q ≠ 0
The last element of the chain has no real zero.
Instances For
A Sturm chain is nonempty.
The polynomial counted by a Sturm chain is its first entry.
A polynomial admitting a Sturm chain is nonzero.