Documentation

HexRealRootsMathlib.Drivers

One refinement step preserves the root and halves the width. For a squarefree p, iso.refine1 isolates the same real root as iso (a root lies in iso's interval iff it lies in the refined interval) and its width is exactly half. The fallback branch of refine1 is never taken: the two half-counts sum to 1, so exactly one half certifies.

-rootBound p < rootBound p, so the initial interval is nonempty.

The ±rootBound variation gap equals ZPoly.rootCount. The Sturm variation difference between -rootBound p and rootBound p counts the real roots of p in (-R, R], which is every real root (Cauchy bound), i.e. ZPoly.rootCount p. This is a statement about p's roots only — the chain elements' own (possibly larger) zeros never enter, so there is no ±R-versus-±∞ gap.

The initial interval's width fits the depth budget. For positive-degree p, 2 · rootBound p ≤ 2 ^ (isolationDepth p − sepPrec p), which is the depth-sufficiency hypothesis the sturmVisit induction consumes at the top.

Dyadic is reflexive (routed through toRat, staying in the core instances that DyadicInterval uses).

theorem HexRealRootsMathlib.dle_of_lt {a b : Dyadic} (h : a < b) :
a b

Dyadic < implies .

theorem HexRealRootsMathlib.dle_trans {a b c : Dyadic} (h1 : a b) (h2 : b c) :
a c

Transitivity of the core dyadic .

sturmVarAt is antitone in the point: the count over (a, b] is a nonnegative cardinality, so the variation at b is at most the one at a.

A real root of the real cast is a complex root of the complex cast.

Separation caps the count. An interval no wider than 2^(−sepPrec p) holds at most one real root of a positive-degree squarefree p (two distinct real roots are more than 4·2^(−sepPrec p) apart by sepPrec_separates'), so its exact Sturm count is at most 1.

theorem HexRealRootsMathlib.assemble?_isSome {p : Hex.ZPoly} {chain : Array Hex.ZPoly} (hchain : chain = p.sturmChain) (arr : Array (Hex.RealRootIsolation p)) (hord : ∀ (i j : Fin arr.size), i < jarr[i].interval.upper arr[j].interval.lower) (hsize : arr.size = Hex.sturmVarNegInf chain - Hex.sturmVarPosInf chain) :
(Hex.assemble? p chain hchain arr).isSome = true

The final assembly step succeeds once its two invariants are witnessed.

The Sturm engine succeeds on nonzero squarefree input. Positive degree is the real content (isolateSturm?_isSome_of_degree_pos); a nonzero constant certifies through the empty chain.

The p ≠ 0 hypothesis is necessary because SquareFreeRat 0 is vacuous while ZPoly.isolateSturm? 0 = none.

The top-level driver succeeds on nonzero squarefree input. A one-liner over isolateSturm?_isSome: ZPoly.isolateRealRoots? keeps whichever engine's certified output arrives first, and the Sturm engine always has one.