Documentation

Ratpoints.Proof.SturmCoverage

The Sturm step keeps every point #

Assuming Sturm's theorem (Ratpoints.SturmTheorem), the intervals that the Sturm step (Ratpoints.Sturm.computeSturm) leaves hold every value x with |x| ≤ 2 ^ 63 and f(x) ≥ 0 of the caller's intervals (Ratpoints.Sturm.covers_computeSturm); the bisection keeps at most 1 + ⌊d / 2⌋ intervals, the room of the array ivlocal of the C code (Ratpoints.Sturm.size_run_iterate_le_of_chain_eq_some), and the intersection with the caller's intervals has at most ⌊d / 2⌋ intervals more than they, within the room that the caller's array must have (Ratpoints.Sturm.size_run_computeSturm_le).

The bisection (Ratpoints.Sturm.iterate) keeps the invariant Ratpoints.Sturm.IterateInvariant: its intervals are intervals of the bisection (Ratpoints.Sturm.EndsWF), and the counts and signs it hands on are those of the real polynomial f at their ends, since the rows of the chain are, over ℝ, positive multiples of the entries of the Sturm sequence of f and f' (Ratpoints.Sturm.IsChain.signsOf, Ratpoints.Sturm.IsChain.run_countsAtInfinity_eq). An interval that it drops holds no x with f(x) ≥ 0 (Ratpoints.Sturm.IterateInvariant.not_kept, from Ratpoints.eval_neg_of_vLeft_eq_vRight); one that it keeps holds every value between the doubles of its ends (Ratpoints.Sturm.covers_addInterval) and a point where f is positive (Ratpoints.Sturm.IterateInvariant.exists_pos, from Ratpoints.exists_inside_eval_pos); and a value x with f(x) ≥ 0 that an interval it splits would keep is kept by one of its halves (Ratpoints.Sturm.kept_halves), where at a simple root m the signs of f'(m) that the halves get decide which. Between two intervals it keeps, f is negative, so that their positive points and the negative points between them alternate in sign, and a polynomial of degree d changes its sign at most d times (Ratpoints.Sturm.length_le_of_witnessed).

Main definitions #

Main statements #

noncomputable def Ratpoints.Sturm.lowerEnd (nl del : Int64) :

The lower end nl / 2 ^ del of an interval of the bisection over ℝ, none for the end -LONG_MAX at -∞.

Equations
Instances For
    noncomputable def Ratpoints.Sturm.upperEnd (nr der : Int64) :

    The upper end nr / 2 ^ der of an interval of the bisection over ℝ, none for the end LONG_MAX at +∞.

    Equations
    Instances For
      theorem Ratpoints.Sturm.EndsWF.lt_ends {depth : ℕ} {nl nr del der : Int64} (h : EndsWF depth nl nr del der) (a : ℝ) :
      a ∈ lowerEnd nl del → ∀ b ∈ upperEnd nr der, a < b

      The real ends of an interval of the bisection are in order.

      structure Ratpoints.Sturm.IterateInvariant (F : Polynomial ℝ) (depth : ℕ) (nl nr del der : Int64) (cl cr : ℕ) (sl sr : ℤ) :

      The invariant of the bisection Ratpoints.Sturm.iterate on the interval from nl / 2 ^ del to nr / 2 ^ der at the depth depth, for the real polynomial F whose chain it evaluates: an interval of the bisection (Ratpoints.Sturm.EndsWF) whose counts cl, cr and signs sl, sr are those of F at its ends (Ratpoints.vLeft, Ratpoints.vRight, Ratpoints.sgnLeftEnd, Ratpoints.sgnRightEnd).

      • ends : EndsWF depth nl nr del der

        An interval of the bisection at the depth.

      • cl_eq : cl = vLeft F (lowerEnd nl del)

        The count at the lower end.

      • cr_eq : cr = vRight F (upperEnd nr der)

        The count at the upper end.

      • sl_eq : sl = ↑(sgnLeftEnd F (lowerEnd nl del))

        The sign just inside the lower end.

      • sr_eq : sr = ↑(sgnRightEnd F (upperEnd nr der))

        The sign just inside the upper end.

      Instances For
        def Ratpoints.Sturm.Kept (nl nr del der : Int64) (sl sr : ℤ) (x : ℚ) :

        The values x that the bisection of an interval keeps: between the values of the doubles of its ends, at a finite end only when F is positive just inside it.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          theorem Ratpoints.Sturm.Kept.le {nl nr del der : Int64} {sl sr : ℤ} {x : ℚ} (h : Kept nl nr del der sl sr x) :
          endValue nl del ≤ x ∧ x ≤ endValue nr der
          theorem Ratpoints.Sturm.Kept.inside_or {nl nr del der : Int64} {sl sr : ℤ} {x : ℚ} (h : Kept nl nr del der sl sr x) :
          Inside (lowerEnd nl del) (upperEnd nr der) ↑x ∨ nl ≠ -longMax ∧ x = endValue nl del ∧ 0 < sl ∨ nr ≠ longMax ∧ x = endValue nr der ∧ 0 < sr

          A value that the bisection of an interval keeps lies between its real ends, or at a finite end where F is positive just inside.

          theorem Ratpoints.Sturm.IterateInvariant.not_kept (hS : SturmTheorem) {F : Polynomial ℝ} (hF : Squarefree F) {depth : ℕ} {nl nr del der : Int64} {cl cr : ℕ} {sl sr : ℤ} (hI : IterateInvariant F depth nl nr del der cl cr sl sr) (hc : cl = cr) (hsl : sl < 0) {x : ℚ} (hx : 0 ≤ Polynomial.eval (↑x) F) :
          ¬Kept nl nr del der sl sr x

          By Sturm's theorem, an interval that the bisection drops, with equal counts at its ends and F negative just inside its lower end, holds no value x with F(x) ≥ 0 that it would keep.

          theorem Ratpoints.Sturm.IterateInvariant.halves {F : Polynomial ℝ} {depth : ℕ} {nl nr del der : Int64} {cl cr : ℕ} {sl sr : ℤ} (hI : IterateInvariant F depth nl nr del der cl cr sl sr) (hd : depth < 55) {nm dem : Int64} (hm : midpoint nl nr del der = (nm, dem)) {s0 s1 : ℤ} {cmid : ℕ} (h0 : s0 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) F))) (h1 : s1 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) (Polynomial.derivative F)))) (hc : cmid = sturmV F ↑(endValue nm dem)) :
          IterateInvariant F (depth + 1) nl nm del dem cl (if s0 = 0 then cmid + 1 else cmid) sl (if s0 = 0 then -s1 else s0) ∧ IterateInvariant F (depth + 1) nm nr dem der cmid cr (if s0 = 0 then s1 else s0) sr

          The halves at the midpoint m = nm / 2 ^ dem of an interval of the bisection keep the invariant with the counts and signs that Ratpoints.Sturm.iterate hands them, when s0, s1 and cmid are the signs of F(m) and F'(m) and the count V(m).

          theorem Ratpoints.Sturm.kept_halves {F : Polynomial ℝ} (hF : Squarefree F) {nl nr del der nm dem : Int64} {sl sr s0 s1 : ℤ} (h0 : s0 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) F))) (h1 : s1 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) (Polynomial.derivative F)))) {x : ℚ} (hx : 0 ≤ Polynomial.eval (↑x) F) (hc : Kept nl nr del der sl sr x) :
          Kept nl nm del dem sl (if s0 = 0 then -s1 else s0) x ∨ Kept nm nr dem der (if s0 = 0 then s1 else s0) sr x

          A value x with F(x) ≥ 0 that the bisection of an interval keeps is kept by one of its halves at the midpoint m, with the signs that Ratpoints.Sturm.iterate hands them: at m itself by the left half when F(m) > 0 or F'(m) < 0, and by the right half when F'(m) > 0.

          theorem Ratpoints.Sturm.covers_addInterval {depth : ℕ} {nl nr del der : Int64} (hE : EndsWF depth nl nr del der) (hd : depth ≤ 55) {acc : Array (Double × Double)} (hacc : ∀ i ∈ acc.toList, IsInterval i) (hb : ∀ i ∈ acc.back?, doubleValue i.2.bits ≤ WithBotTop.coe (endValue nl del)) {sl sr : ℤ} :
          (∀ (x : ℚ), InIntervals (domainValues acc.toList) x → InIntervals (domainValues (addInterval acc nl nr del der).toList) x) ∧ ∀ (x : ℚ), Kept nl nr del der sl sr x → InIntervals (domainValues (addInterval acc nl nr del der).toList) x

          The intervals kept hold what they held, and every value between the ends of an interval of the bisection, after the bisection keeps that interval.

          The signs and the count that Ratpoints.Sturm.signsAt computes for the chain rows at the finite points nm / 2 ^ dem with 0 ≤ dem ≤ 55 are those of the real polynomial F.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            theorem Ratpoints.Sturm.SignsOf.midpoint {F : Polynomial ℝ} {rows : Array (Array ℤ)} {k : ℕ} (h : SignsOf F rows k) {depth : ℕ} {nl nr del der nm dem : Int64} (hE : EndsWF depth nl nr del der) (hd : depth < 55) (hm : Sturm.midpoint nl nr del der = (nm, dem)) {s0 s1 : ℤ} {cmid : ℕ} (hs : (signsAt rows k nm dem).run = (s0, s1, cmid)) :
            s0 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) F)) ∧ s1 = ↑(SignType.sign (Polynomial.eval (↑(endValue nm dem)) (Polynomial.derivative F))) ∧ cmid = sturmV F ↑(endValue nm dem)

            The signs and the count at the midpoint of an interval of the bisection, below the depth 55.

            theorem Ratpoints.Sturm.covers_iterate (hS : SturmTheorem) {F : Polynomial ℝ} (hF : Squarefree F) {rows : Array (Array ℤ)} {k iter : ℕ} (hsig : SignsOf F rows k) (hit : iter ≤ 55) {nl nr del der : Int64} {cl cr : ℕ} {sl sr : ℤ} {depth : ℕ} {acc : Array (Double × Double)} (hI : IterateInvariant F depth nl nr del der cl cr sl sr) (hd : depth ≤ iter) (hacc : AreIntervals acc.toList) (hb : ∀ i ∈ acc.back?, doubleValue i.2.bits ≤ WithBotTop.coe (endValue nl del)) :
            (∀ (x : ℚ), InIntervals (domainValues acc.toList) x → InIntervals (domainValues (iterate rows k iter nl nr del der cl cr sl sr depth acc).run.toList) x) ∧ ∀ (x : ℚ), 0 ≤ Polynomial.eval (↑x) F → Kept nl nr del der sl sr x → InIntervals (domainValues (iterate rows k iter nl nr del der cl cr sl sr depth acc).run.toList) x

            By Sturm's theorem, the bisection Ratpoints.Sturm.iterate of an interval with the invariant Ratpoints.Sturm.IterateInvariant of a squarefree F, up to the depth iter ≤ 55, keeps what the intervals kept so far hold, and every value with F ≥ 0 that it keeps (Ratpoints.Sturm.Kept).

            theorem Ratpoints.Sturm.squarefree_chainPoly {c : List ℤ} {d : ℕ} (hd : 1 ≤ d) (hc : c.getD d 0 ≠ 0) {rows : Array (Array ℤ)} (h : (chain c d).run = some rows) :

            The real polynomial of the chain of c and d is squarefree when the chain succeeds: over ℚ by Ratpoints.Sturm.run_chain_eq_none_iff, and a separable polynomial stays separable over ℝ.

            The invariant of the bisection on the whole line, with the counts and signs of F at ∓∞.

            theorem Ratpoints.Sturm.kept_neg_longMax_longMax_of_abs_le {sl sr : ℤ} {x : ℚ} (hx : |x| ≤ 2 ^ 63) :
            Kept (-longMax) longMax 0 0 sl sr x

            The bisection of the whole line keeps every value x with |x| ≤ 2 ^ 63, the values of the doubles of its ends ∓LONG_MAX.

            theorem Ratpoints.Sturm.IsChain.signsOf {c : List ℤ} {d : ℕ} {rows : Array (Array ℤ)} (h : IsChain c d rows) (h1 : rows.back!.size = 1) (hd : d < 2 ^ 57) (hF : Squarefree (chainPoly c d)) :
            SignsOf (chainPoly c d) rows (rows.size - 1)

            For a chain whose last row is constant, of a polynomial of degree d < 2 ^ 57 that is squarefree over ℝ, Ratpoints.Sturm.signsAt computes the signs and the count of the real polynomial (Ratpoints.Sturm.IsChain.run_signsAt_eq).

            theorem Ratpoints.Sturm.IsChain.sgnRightEnd_none {c : List ℤ} {d : ℕ} {rows : Array (Array ℤ)} (h : IsChain c d rows) :
            ↑(sgnRightEnd (chainPoly c d) none) = (c.getD d 0).sign

            The sign of the real polynomial of a chain at +∞, that of c_d.

            theorem Ratpoints.Sturm.IsChain.sgnLeftEnd_none {c : List ℤ} {d : ℕ} {rows : Array (Array ℤ)} (h : IsChain c d rows) :
            ↑(sgnLeftEnd (chainPoly c d) none) = if d % 2 = 1 then -(c.getD d 0).sign else (c.getD d 0).sign

            The sign of the real polynomial of a chain at -∞, that of c_d, negated for odd d.

            theorem Ratpoints.Sturm.isChain_of_run_chain_eq_some {c : List ℤ} {d : ℕ} (hd : 1 ≤ d) (hc : c.getD d 0 ≠ 0) {rows : Array (Array ℤ)} (h : (chain c d).run = some rows) :
            IsChain c d rows ∧ rows.back!.size = 1

            A chain that succeeds on a polynomial of degree d ≥ 1 with c_d ≠ 0: a chain whose last row is constant.

            theorem Ratpoints.Sturm.covers_computeSturm (hS : SturmTheorem) {c : List ℤ} {d iter : ℕ} {ivs iv' : Array (Double × Double)} (hd : 1 ≤ d) (hcd : c.getD d 0 ≠ 0) (hd57 : d < 2 ^ 57) (hit : iter ≤ 55) (hwf : IntervalsWF (domainBits ivs.toList)) (h : (computeSturm c d iter ivs).run = some iv') {x : ℚ} (hx : 0 ≤ Polynomial.eval (↑x) (chainPoly c d)) (hb : |x| ≤ 2 ^ 63) (hxi : InIntervals (domainValues ivs.toList) x) :

            By Sturm's theorem, the Sturm step at a depth of at most 55 on a polynomial of degree 1 ≤ d < 2 ^ 57 with c_d ≠ 0, for well-formed intervals of the caller, leaves intervals that hold every value x with |x| ≤ 2 ^ 63 and f(x) ≥ 0 in the caller's intervals.

            The size of the intervals kept #

            theorem Ratpoints.Sturm.abs_endValue_le {n e : Int64} (hn : n.toInt.natAbs ≤ 2 ^ 53) (he : 0 ≤ e.toInt) :
            |endValue n e| ≤ 2 ^ 53

            A finite end of the bisection has a value of at most 2 ^ 53 in absolute value.

            theorem Ratpoints.Sturm.EndsWF.neg_two_pow_le_endValue_and_endValue_le {depth : ℕ} {nl nr del der : Int64} (h : EndsWF depth nl nr del der) (hd : depth ≤ 55) :
            -2 ^ 63 ≤ endValue nl del ∧ endValue nr der ≤ 2 ^ 63

            The ends of an interval of the bisection up to the depth 55 have values in [-2 ^ 63, 2 ^ 63].

            The ends of an interval of doubles have rational values L and U in [-2 ^ 63, 2 ^ 63], and the real polynomial F is positive at a point p above L and below U, where an end of the value ∓2 ^ 63, the value of an end at infinity of the bisection, does not bound p.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem Ratpoints.Sturm.witnessed_join {F : Polynomial ℝ} {lo up u : Double} {L U : ℚ} (hlo : IsInterval (lo, up) ∧ Witnessed F (lo, up)) (hv : doubleValue up.bits = WithBotTop.coe L) (hu : doubleValue u.bits = WithBotTop.coe U) (hU : U ≤ 2 ^ 63) (hp : ∃ (p : ℝ), 0 < Polynomial.eval p F ∧ (-2 ^ 63 < L → ↑L ≤ p) ∧ (U < 2 ^ 63 → p ≤ ↑U)) :

              The interval from lo to u that joins the interval up to u with the value U to the last interval (lo, up) kept, where up has the value L of the new lower end, is witnessed by the witness of the new interval.

              theorem Ratpoints.Sturm.witnessed_addInterval {F : Polynomial ℝ} {acc : Array (Double × Double)} {nl nr del der : Int64} {L U : ℚ} (hacc : ∀ i ∈ acc.toList, IsInterval i ∧ Witnessed F i) (hl : HasValue ((Double.ofInt64 nl).ldexp (-del.toInt)) L) (hu : HasValue ((Double.ofInt64 nr).ldexp (-der.toInt)) U) (hL : -2 ^ 63 ≤ L) (hU : U ≤ 2 ^ 63) (hp : ∃ (p : ℝ), 0 < Polynomial.eval p F ∧ (-2 ^ 63 < L → ↑L ≤ p) ∧ (U < 2 ^ 63 → p ≤ ↑U)) (i : Double × Double) :
              i ∈ (addInterval acc nl nr del der).toList → Witnessed F i

              The intervals kept stay witnessed when the bisection adds one from l to u with a positive point after them: a join extends the last interval with the witness of the new one.

              theorem Ratpoints.Sturm.IterateInvariant.exists_pos (hS : SturmTheorem) {F : Polynomial ℝ} (hF : Squarefree F) {depth : ℕ} {nl nr del der : Int64} {cl cr : ℕ} {sl sr : ℤ} (hI : IterateInvariant F depth nl nr del der cl cr sl sr) (h : ¬(cl = cr ∧ sl < 0)) :
              ∃ (p : ℝ), 0 < Polynomial.eval p F ∧ (-2 ^ 63 < endValue nl del → ↑(endValue nl del) ≤ p) ∧ (endValue nr der < 2 ^ 63 → p ≤ ↑(endValue nr der))

              By Sturm's theorem, an interval that the bisection keeps, without equal counts at its ends and F negative just inside its lower end, holds a point where F is positive: next to a root between its ends, or just inside its lower end.

              theorem Ratpoints.Sturm.witnessed_iterate (hS : SturmTheorem) {F : Polynomial ℝ} (hF : Squarefree F) {rows : Array (Array ℤ)} {k iter : ℕ} (hsig : SignsOf F rows k) (hit : iter ≤ 55) {nl nr del der : Int64} {cl cr : ℕ} {sl sr : ℤ} {depth : ℕ} {acc : Array (Double × Double)} (hI : IterateInvariant F depth nl nr del der cl cr sl sr) (hd : depth ≤ iter) (hacc : AreIntervals acc.toList) (hb : ∀ i ∈ acc.back?, doubleValue i.2.bits ≤ WithBotTop.coe (endValue nl del)) (hw : ∀ i ∈ acc.toList, Witnessed F i) (i : Double × Double) :
              i ∈ (iterate rows k iter nl nr del der cl cr sl sr depth acc).run.toList → Witnessed F i

              By Sturm's theorem, the bisection of an interval with the invariant of a squarefree F, up to the depth iter ≤ 55, after witnessed intervals, keeps witnessed intervals (Ratpoints.Sturm.Witnessed).

              theorem Ratpoints.Sturm.eval_neg_of_lt_of_lt {F : Polynomial ℝ} {i j : Double × Double} {l : List (Double × Double)} {A : ℚ} (hiv : ∀ k ∈ i :: j :: l, IsInterval k) (hp : List.Pairwise EndsBefore (i :: j :: l)) (hgap : ∀ (x : ℚ), A ≤ x → x ≤ 2 ^ 63 → 0 ≤ Polynomial.eval (↑x) F → InIntervals (domainValues (i :: j :: l)) x) {q : ℚ} (hAq : A ≤ q) (hq : q ≤ 2 ^ 63) (hiq : doubleValue i.2.bits < WithBotTop.coe q) (hqj : WithBotTop.coe q < doubleValue j.1.bits) :
              Polynomial.eval (↑q) F < 0

              Between two neighbouring intervals of intervals increasing and strictly apart that hold every value x ≥ A up to 2 ^ 63 with F(x) ≥ 0, F is negative.

              theorem Ratpoints.Sturm.inIntervals_domainValues_cons_of_doubleValue_le {F : Polynomial ℝ} {i j : Double × Double} {l : List (Double × Double)} {A : ℚ} (hiv : ∀ k ∈ i :: j :: l, IsInterval k) (hp : List.Pairwise EndsBefore (i :: j :: l)) (hA : WithBotTop.coe A ≤ doubleValue i.1.bits) (hgap : ∀ (x : ℚ), A ≤ x → x ≤ 2 ^ 63 → 0 ≤ Polynomial.eval (↑x) F → InIntervals (domainValues (i :: j :: l)) x) (x : ℚ) (hx : doubleValue j.1.bits ≤ WithBotTop.coe x) (hx2 : x ≤ 2 ^ 63) (hF : 0 ≤ Polynomial.eval (↑x) F) :

              The values x ≥ L_j with F(x) ≥ 0 held by intervals i :: j :: l increasing and strictly apart are held by j :: l, when the first interval begins at A ≤ x at the earliest.

              theorem Ratpoints.Sturm.exists_isChain_cons_cons {F : Polynomial ℝ} {i j : Double × Double} {l : List (Double × Double)} {A : ℚ} (hw : Witnessed F i) (hwj : Witnessed F j) (hiv : ∀ k ∈ i :: j :: l, IsInterval k) (hp : List.Pairwise EndsBefore (i :: j :: l)) (hA : WithBotTop.coe A ≤ doubleValue i.1.bits) (hgap : ∀ (x : ℚ), A ≤ x → x ≤ 2 ^ 63 → 0 ≤ Polynomial.eval (↑x) F → InIntervals (domainValues (i :: j :: l)) x) {y : ℝ} {ys : List ℝ} (hch : List.IsChain (fun (a b : ℝ) => a < b ∧ Polynomial.eval a F * Polynomial.eval b F < 0) (y :: ys)) (hy0 : 0 < Polynomial.eval y F) (hyl : ∀ (L : ℚ), doubleValue j.1.bits = WithBotTop.coe L → -2 ^ 63 < L → ↑L ≤ y) :
              ∃ (y' : ℝ) (q : ℝ), List.IsChain (fun (a b : ℝ) => a < b ∧ Polynomial.eval a F * Polynomial.eval b F < 0) (y' :: q :: y :: ys) ∧ 0 < Polynomial.eval y' F ∧ ∀ (L : ℚ), doubleValue i.1.bits = WithBotTop.coe L → -2 ^ 63 < L → ↑L ≤ y'

              The step of Ratpoints.Sturm.exists_isChain_of_witnessed: points of alternating signs for j :: l, the first positive and above the lower end of j, are preceded by the positive point of i and a negative point between i and j.

              theorem Ratpoints.Sturm.exists_isChain_of_witnessed {F : Polynomial ℝ} {i : Double × Double} {l : List (Double × Double)} {A : ℚ} (hw : ∀ j ∈ i :: l, Witnessed F j) (hiv : ∀ j ∈ i :: l, IsInterval j) (hp : List.Pairwise EndsBefore (i :: l)) (hA : WithBotTop.coe A ≤ doubleValue i.1.bits) (hgap : ∀ (x : ℚ), A ≤ x → x ≤ 2 ^ 63 → 0 ≤ Polynomial.eval (↑x) F → InIntervals (domainValues (i :: l)) x) :
              ∃ (y : ℝ) (ys : List ℝ), ys.length = 2 * l.length ∧ List.IsChain (fun (a b : ℝ) => a < b ∧ Polynomial.eval a F * Polynomial.eval b F < 0) (y :: ys) ∧ 0 < Polynomial.eval y F ∧ ∀ (L : ℚ), doubleValue i.1.bits = WithBotTop.coe L → -2 ^ 63 < L → ↑L ≤ y

              Witnessed intervals, increasing and strictly apart, that hold every value x ≥ A up to 2 ^ 63 with F(x) ≥ 0, the first beginning at A at the earliest, give increasing points at which the signs of F alternate: a positive point in each interval, the first one above the lower end of the first interval unless that is -2 ^ 63, and a negative point between each two.

              theorem Ratpoints.Sturm.length_le_of_witnessed {F : Polynomial ℝ} (hF : F ≠ 0) {l : List (Double × Double)} (hw : ∀ i ∈ l, Witnessed F i) (hiv : ∀ i ∈ l, IsInterval i) (hp : List.Pairwise EndsBefore l) (hgap : ∀ (x : ℚ), -2 ^ 63 ≤ x → x ≤ 2 ^ 63 → 0 ≤ Polynomial.eval (↑x) F → InIntervals (domainValues l) x) :

              Witnessed intervals, increasing and strictly apart, that hold every value in [-2 ^ 63, 2 ^ 63] with F ≥ 0, are at most 1 + n / 2 for a nonzero F of degree n: their positive points and the negative points between them are 2 m - 1 points of alternating signs (Polynomial.length_le_natDegree_add_one_of_isChain).

              theorem Ratpoints.Sturm.IsChain.natDegree_chainPoly {c : List ℤ} {d : ℕ} {rows : Array (Array ℤ)} (h : IsChain c d rows) :

              The real polynomial of a chain of c and d has the degree d.

              theorem Ratpoints.Sturm.size_run_iterate_le_of_chain_eq_some (hS : SturmTheorem) {c : List ℤ} {d iter : ℕ} (hd : 1 ≤ d) (hcd : c.getD d 0 ≠ 0) (hd57 : d < 2 ^ 57) (hit : iter ≤ 55) {rows : Array (Array ℤ)} (hrows : (chain c d).run = some rows) :
              (iterate rows (rows.size - 1) iter (-longMax) longMax 0 0 (countsAtInfinity rows (rows.size - 1)).run.2 (countsAtInfinity rows (rows.size - 1)).run.1 (if d % 2 = 1 then -(c.getD d 0).sign else (c.getD d 0).sign) (c.getD d 0).sign 0 #[]).run.size ≤ 1 + d / 2

              By Sturm's theorem, the bisection of the Sturm step at a depth of at most 55, for a polynomial of degree 1 ≤ d < 2 ^ 57 with c_d ≠ 0 whose chain succeeds, keeps at most 1 + ⌊d / 2⌋ intervals: each holds a point where f is positive, and f is negative between two of them.

              theorem Ratpoints.Sturm.size_run_computeSturm_le (hS : SturmTheorem) {c : List ℤ} {d iter : ℕ} (hd : 1 ≤ d) (hcd : c.getD d 0 ≠ 0) (hd57 : d < 2 ^ 57) (hit : iter ≤ 55) {iv iv' : Array (Double × Double)} (h : (computeSturm c d iter iv).run = some iv') :
              iv'.size ≤ iv.size + d / 2

              By Sturm's theorem, the intersection of the intervals of the Sturm step at a depth of at most 55, for a polynomial of degree 1 ≤ d < 2 ^ 57 with c_d ≠ 0, with the intervals iv of the caller has at most iv.size + ⌊d / 2⌋ intervals (from Ratpoints.Sturm.size_run_iterate_le_of_chain_eq_some): within both the room num_inter + degree that the manual asks of the caller's array and the room of 1 + ⌊degree / 2⌋ intervals more than it holds that the C code relies on (sturm.c:52-53), the latter from the degree 3 on only by the bound with ⌊d / 2⌋.

              The value of the real polynomial of the chain of c and its degree at a rational point.

              theorem Ratpoints.Sturm.eval_chainPoly_nonneg {c : List ℤ} {a : ℤ} {b : ℕ} (hb : 0 < b) (h : 0 ≤ binaryForm c a ↑b) :
              0 ≤ Polynomial.eval (↑(↑a / ↑b)) (chainPoly c (degree c))

              The real polynomial of the chain of c and its degree is not negative at a / b, b > 0, when the binary form is not negative at (a, b).