Documentation

Ratpoints.Proof.Stages

The contracts of the stages of the sieve #

The test for common factors on the 64-bit words of the C code (Ratpoints.Sieve.relprime) decides whether a numerator is prime to the denominator, and none of its operations leaves the range of a long. For a numerator a prime to the denominator b with |a| ≤ H, the third stage (Ratpoints.Sieve.stage3) with the sieve entries of primes 1 < p ≤ 2 ^ 32 with their tables and reciprocals (Ratpoints.Sieve.SieveEntry.IsPrimeEntry) is the test of the rows of these entries: it reads the table of each prime at a b⁻¹ mod p, in both branches of the bias, and a prime that divides b admits every numerator prime to b; the values that the C code holds in longs stay in range. The exact check (Ratpoints.Sieve.checkPoint) and the points at infinity (Ratpoints.Sieve.pointsAtInfinity), on a delivery whose flag of the stop is clear, are the reference of the delivery (Ratpoints.Delivery.deliver) of the lists of the points they deliver for the flags of the search: the points of the check of the reference, without the point with y < 0 under RATPOINTS_NO_Y, or the one survivor with y = 0 under RATPOINTS_NO_CHECK, mapped back after a reversal. So the test of a candidate (Ratpoints.Sieve.accepted), for |a| < 2 ^ 63 and 0 < b < 2 ^ 63, followed by the exact check, delivers the points of the check with the flags (Ratpoints.Sieve.checkNumWith), which is the check of the reference (Ratpoints.Sieve.checkNum) with the flags of the output clear, for the numerators that survive these entries. The second stage on a bit array (Ratpoints.Sieve.secondStage), or on one of its words (Ratpoints.Sieve.secondStageWord), with moduli in the range of the packing and their reciprocals and the test small of the piece, gives its words and-ed with the rows of all its moduli at their offsets (Ratpoints.Sieve.andWords), although it stops when the bit array or the word is zero. The contracts of the loops are @[spec] theorems proved with vcgen, the program logic of Lean core, with loop invariants that are named definitions.

Main definitions #

Main statements #

Implementation notes #

The file uses Lean core and Std only, as Ratpoints.Proof.Delivery and Ratpoints.Proof.Words do; the second stage builds on the words of the rows of the latter (Ratpoints.Sieve.SieveSpec.wordAt, Ratpoints.Sieve.andWords) and on its reading of the reciprocals in step with the moduli (Ratpoints.Sieve.eq_magic_and_of_next?_eq_some, Ratpoints.Sieve.next?_ne_none_of_lt). The proofs use only the facts on the constants that decide checks next to them, that Ratpoints.mulModLimit < 2 ^ 32 and Ratpoints.stage3Limit ≤ 2 ^ 32, never their values. The words of the test for common factors are read as natural numbers by Int64.toNatClampNeg, which is faithful on the non-negative words that the binary algorithm keeps; the facts on words that are not about the model are in Ratpoints.Proof.Bits.

The test for common factors #

The invariant of the loop of Ratpoints.Sieve.relprimeOdd, whose state is (m, n): both words are odd as natural numbers (Int64.toNatClampNeg), and so positive, they have the gcd g of the operands, and m = n at the exit.

Equations
  • One or more equations did not get rendered due to their size.
Instances For
    theorem Ratpoints.Sieve.RelprimeOddInvariant.toUInt64_ne_zero {g k : Nat} {m n : Int64} (hmn : (n != m) = true) (h : m.toNatClampNeg + n.toNatClampNeg = k ∧ RelprimeOddInvariant g false (m, n)) :
    ¬((m - n ^^^ (m - n) >>> 63) - (m - n) >>> 63).toUInt64 = 0

    In the loop of Ratpoints.Sieve.relprimeOdd, from m ≠ n, the absolute value of the difference is a word other than 0, whose lowest set bit RP_CTZL may look for.

    theorem Ratpoints.Sieve.RelprimeOddInvariant.shiftRight_min {g k t : Nat} {m n d : Int64} (hmn : (n != m) = true) (h : m.toNatClampNeg + n.toNatClampNeg = k ∧ RelprimeOddInvariant g false (m, n)) (hd : d = (m - n ^^^ (m - n) >>> 63) - (m - n) >>> 63) (ht : t = d.toUInt64.toBitVec.ctz.toNat) :
    (d >>> Int64.ofNat t).toNatClampNeg + (n + (m - n &&& (m - n) >>> 63)).toNatClampNeg < k ∧ RelprimeOddInvariant g false (d >>> Int64.ofNat t, n + (m - n &&& (m - n) >>> 63))

    A step of the loop of Ratpoints.Sieve.relprimeOdd from m ≠ n, in the shape of the verification condition: n becomes the smaller of the two and m the odd part of their distance d, which keep what the loop keeps, and their sum, the measure, decreases.

    At the exit of the loop of Ratpoints.Sieve.relprimeOdd, m = n is the gcd g.

    The loop ends, since the sum of the two values decreases, and it ends at m = n = gcd(m, n); no operation leaves the range of a long, since the values stay positive.

    theorem Ratpoints.Sieve.relprime_spec (m n : Int64) :
    ⦃ Int64.minValue < m ∧ 0 < n ⦄ relprime m n ⦃ fun (r : Bool) => r = decide (m.toInt.gcd n.toInt = 1) ⦄

    The binary algorithm decides whether the numerator m is prime to the denominator n ≥ 1, for m other than -2 ^ 63, whose negation would leave the range of a long; no operation leaves it.

    The third stage #

    Whether the third stage lets the numerator a through the prime of cs: when the prime divides the denominator (binv = 0), or when its table marks the residue at which the stage reads it (Ratpoints.Sieve.CheckSpec.index).

    Equations
    Instances For
      def Ratpoints.Sieve.Stage3Invariant (a : Int) (checks pref suff : List CheckSpec) (st : Option Bool × PUnit) :

      The invariant of the loop of Ratpoints.Sieve.stage3 over checks, after the checks pref with the checks suff still to come, on the result of an early return: without one, the checks so far let a through; with one, at the end, the result is whether all the checks do.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For
        theorem Ratpoints.Sieve.Stage3Invariant.push {a : Int} {checks pref suff : List CheckSpec} {cur : CheckSpec} {o : Option Bool} {u : PUnit} (h : Stage3Invariant a checks pref (cur :: suff) (o, u)) (hc : cur.admits a = true) :
        Stage3Invariant a checks (pref ++ [cur]) suff (none, PUnit.unit)
        theorem Ratpoints.Sieve.stage3Invariant_some_false {a : Int} {checks pref suff : List CheckSpec} {cur : CheckSpec} (hl : checks = pref ++ cur :: suff) (hc : cur.admits a = false) :
        theorem Ratpoints.Sieve.Stage3Invariant.eq_all_of_some {a : Int} {checks : List CheckSpec} {o : Option Bool} {u : PUnit} {r : Bool} (h : Stage3Invariant a checks checks [] (o, u)) (ho : (o, u).fst = some r) :
        r = checks.all fun (x : CheckSpec) => x.admits a
        theorem Ratpoints.Sieve.Stage3Invariant.true_eq_all_of_none {a : Int} {checks : List CheckSpec} {o : Option Bool} {u : PUnit} (h : Stage3Invariant a checks checks [] (o, u)) (ho : (o, u).fst = none) :
        true = checks.all fun (x : CheckSpec) => x.admits a
        theorem Ratpoints.Sieve.stage3_spec (a : Int) (checks : List CheckSpec) :
        ⦃ True ⦄ stage3 a checks ⦃ fun (r : Bool) => r = checks.all fun (x : CheckSpec) => x.admits a ⦄

        The third stage stops at the first prime that rejects the numerator, which is what all its primes say then.

        @[simp]
        theorem Ratpoints.Sieve.p_checkOf (b H : Nat) (e : SieveEntry) (mg : Nat) :
        (checkOf b H e mg).p = e.p
        @[simp]
        theorem Ratpoints.Sieve.magic_checkOf (b H : Nat) (e : SieveEntry) (mg : Nat) :
        (checkOf b H e mg).magic = e.magic
        theorem Ratpoints.Sieve.bias_checkOf (b H : Nat) {e : SieveEntry} {t : Entry} (he : e.factors = [Factor.prime t]) (mg : Nat) :
        (checkOf b H e mg).bias = if 2 * e.p * H < stage3Limit then e.p * H else 0
        theorem Ratpoints.Sieve.binv_checkOf {b : Nat} (H : Nat) {e : SieveEntry} {t : Entry} (he : e.factors = [Factor.prime t]) (hp : 0 < e.p) (hp32 : e.p ≤ 2 ^ 32) :
        (checkOf b H e (magic e.p)).binv = if b % e.p = 0 then 0 else t.inverses[b % e.p]!

        The inverse of the denominator b that Ratpoints.Sieve.checkOf takes from the table t of the single factor of the sieve entry e of a modulus 0 < p ≤ 2 ^ 32, with the reciprocal of p: 0 when p divides b, and otherwise the entry of t at b mod p, which the reduction by the reciprocal gives for b ≤ Ratpoints.mulModLimit.

        theorem Ratpoints.Sieve.le_mul_add_natCast_mul {a : Int} {p binv H : Nat} (ha : a.natAbs ≤ H) (hb : binv < p) :
        ↑H ≤ a * ↑binv + ↑(p * H)

        The value a binv + p H that the third stage reduces with the bias p H, for |a| ≤ H and binv < p, is at least H (sift.c:303): a natural number.

        theorem Ratpoints.Sieve.mul_add_natCast_mul_le_two_mul_mul_sub {a : Int} {p binv H : Nat} (ha : a.natAbs ≤ H) (hb : binv < p) :
        a * ↑binv + ↑(p * H) ≤ 2 * ↑p * ↑H - ↑H

        The value a binv + p H that the third stage reduces with the bias p H, for |a| ≤ H and binv < p, is at most 2 p H - H (sift.c:303), below the bound 2 p H < Ratpoints.stage3Limit of the bias, and so a long.

        theorem Ratpoints.Sieve.toNat_emod_mul_lt_sq (a : Int) {p binv : Nat} (hb : binv < p) :
        (a % ↑p).toNat * binv < p ^ 2

        The product am binv that the third stage reduces without the bias, of the residue am of the numerator modulo p and the inverse binv < p, is below p ^ 2 (sift.c:307), a long for the moduli below 2 ^ 31.

        theorem Ratpoints.Sieve.mulMod_toNat_mul_add_mul_magic {a : Int} {p binv H : Nat} (ha : a.natAbs ≤ H) (hb : binv < p) (hH : 2 * p * H < 2 ^ 32) :
        mulMod (a * ↑binv + ↑(p * H)).toNat p (magic p) = (a % ↑p).toNat * binv % p

        With the bias p H, for |a| ≤ H, binv < p and 2 p H < 2 ^ 32, the value a binv + p H reduced by the reciprocal of p is the residue of (a mod p) binv: the value is below 2 ^ 32, and so is p unless a = H = 0.

        theorem Ratpoints.Sieve.CheckSpec.index_eq {cs : CheckSpec} {a : Int} {H : Nat} (hb : cs.binv < cs.p) (ha : a.natAbs ≤ H) (hbias : cs.bias ≠ 0 → cs.bias = cs.p * H ∧ 2 * cs.p * H < 2 ^ 32 ∧ cs.magic = Sieve.magic cs.p) :
        cs.index a = (a % ↑cs.p).toNat * cs.binv % cs.p

        The residue at which the third stage reads the table of the prime p of cs for the numerator a with |a| ≤ H is (a mod p) binv mod p, for binv < p, in both branches: with the bias p H, for 2 p H < 2 ^ 32 and the reciprocal of p, and without it.

        theorem Ratpoints.Sieve.bias_checkOf_eq_and_of_ne_zero {b H : Nat} {e : SieveEntry} {t : Entry} (hf : e.factors = [Factor.prime t]) (hm : e.magic = magic e.p) {mg : Nat} (h0 : (checkOf b H e mg).bias ≠ 0) :
        (checkOf b H e mg).bias = (checkOf b H e mg).p * H ∧ 2 * (checkOf b H e mg).p * H < 2 ^ 32 ∧ (checkOf b H e mg).magic = magic (checkOf b H e mg).p

        The bias of what the third stage needs of the entry e of a prime, when it is not 0, is p H with 2 p H < 2 ^ 32, and its reciprocal, that of the entry, is that of p when the entry's is.

        The sieve entry e is that of a modulus 1 < p ≤ 2 ^ 32 whose single factor is a table t of p with inverses of the residues 0 < r < p that are residues 0 < t.inverses[r]! < p, and whose reciprocal is that of p (Ratpoints.Sieve.magic): the shape that the third stage needs of its entries (Ratpoints.Sieve.checkOf), whose rows it then tests (Ratpoints.Sieve.all_admits_fillChecks); the fields of the packing (the bias, the inverses of Ratpoints.rbaLength and of the strides) do not matter. The entry of a prime with the table of the reference has it (Ratpoints.Sieve.isPrimeEntry_examinePrime).

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          theorem Ratpoints.Sieve.SieveEntry.IsPrimeEntry.admits_checkOf {e : SieveEntry} (he : e.IsPrimeEntry) {b H : Nat} {a : Int} (hab : a.gcd ↑b = 1) (ha : a.natAbs ≤ H) :
          (checkOf b H e (Sieve.magic e.p)).admits a = e.admits b a

          The third stage with the entry of a prime 1 < p ≤ 2 ^ 32 whose single factor is its table, of the shape of Ratpoints.Sieve.SieveEntry.IsPrimeEntry, lets a numerator a prime to b with |a| ≤ H through exactly when the row of b in the entry admits it: when p divides b, since then p ∤ a, and otherwise since the stage reads the table at (a mod p) b⁻¹ mod p (Ratpoints.Sieve.CheckSpec.index_eq).

          theorem Ratpoints.Sieve.all_admits_fillChecks {es : List SieveEntry} (hes : ∀ (e : SieveEntry), e ∈ es → e.IsPrimeEntry) {a : Int} {b H : Nat} (hab : a.gcd ↑b = 1) (ha : a.natAbs ≤ H) :
          ((fillChecks b H es (List.map (fun (e : SieveEntry) => magic e.p) es)).all fun (x : CheckSpec) => x.admits a) = survives es b a

          For a numerator a prime to b with |a| ≤ H, what the third stage needs of the sieve entries es of the shape of Ratpoints.Sieve.SieveEntry.IsPrimeEntry, with the reciprocals of their moduli, lets a through exactly when a survives these entries.

          The test of a candidate #

          theorem Ratpoints.Sieve.accepted_spec (a : Int) (b : Nat) (checks : Thunk (List CheckSpec)) (cnt : Counters) :
          ⦃ 0 < b ∧ a.natAbs < 2 ^ 63 ∧ b < 2 ^ 63 ⦄ accepted a b checks cnt ⦃ fun (r : Bool × Counters) => r.fst = (decide (a.gcd ↑b = 1) && checks.get.all fun (x : CheckSpec) => x.admits a) ⦄

          The test for common factors on the words of the numerator |a| < 2 ^ 63 and the denominator 0 < b < 2 ^ 63 is the test on the integers, and the thunk of the third stage is forced only when the numerator is prime to b.

          theorem Ratpoints.Sieve.accepted_value (a : Int) (b : Nat) (checks : Thunk (List CheckSpec)) (cnt : Counters) :
          ⦃ True ⦄ accepted a b checks cnt ⦃ fun (r : Bool × Counters) => r = (accepted a b checks cnt).run ⦄

          The test of a candidate as its value: the walks through the set bits of a word read it so, and their contracts need none of the hypotheses of Ratpoints.Sieve.accepted_spec.

          theorem Ratpoints.Sieve.fst_run_accepted_congr (a : Int) (b : Nat) (checks : Thunk (List CheckSpec)) (cnt cnt' : Counters) :
          (accepted a b checks cnt).run.fst = (accepted a b checks cnt').run.fst

          Whether a numerator passes the test of a candidate does not depend on the counters.

          theorem Ratpoints.Sieve.fst_run_accepted_eq {es : List SieveEntry} (hes : ∀ (e : SieveEntry), e ∈ es → e.IsPrimeEntry) {a : Int} {b H : Nat} {checks : Thunk (List CheckSpec)} (cnt : Counters) (hc : checks.get = fillChecks b H es (List.map (fun (e : SieveEntry) => magic e.p) es)) (hb : 0 < b) (hb63 : b < 2 ^ 63) (ha : a.natAbs ≤ H) (hH : H < 2 ^ 63) :
          (accepted a b checks cnt).run.fst = (decide (a.gcd ↑b = 1) && survives es b a)

          For |a| ≤ H < 2 ^ 63, a denominator 0 < b < 2 ^ 63 and the thunk of what the third stage needs of the sieve entries es of the shape of Ratpoints.Sieve.SieveEntry.IsPrimeEntry, with the reciprocals of their moduli, for b and H, a numerator goes on to the exact check when it is prime to b and survives these entries.

          The counters #

          @[instance_reducible]

          The counters c and k (Ratpoints.Sieve.Counters) added field by field, wrapping as the UInt64s do: the counts of two pieces of work of the sieve, one after the other, as Ratpoints.Sieve.RunCounts.fold adds those of a block to those of the run.

          Equations
          • One or more equations did not get rendered due to their size.
          theorem Ratpoints.Sieve.Counters.ext {x y : Counters} (words : x.words = y.words) (arrays : x.arrays = y.arrays) (bits : x.bits = y.bits) (coprime : x.coprime = y.coprime) (checks : x.checks = y.checks) (sifts : x.sifts = y.sifts) :
          x = y
          @[simp]
          theorem Ratpoints.Sieve.Counters.add_assoc (a b c : Counters) :
          a + b + c = a + (b + c)
          theorem Ratpoints.Sieve.Counters.arrays_add_one (c : Counters) :
          { words := c.words, arrays := c.arrays + 1, bits := c.bits, coprime := c.coprime, checks := c.checks, sifts := c.sifts } = c + { arrays := 1 }
          theorem Ratpoints.Sieve.Counters.words_add_eq (c : Counters) (x : UInt64) :
          { words := c.words + x, arrays := c.arrays, bits := c.bits, coprime := c.coprime, checks := c.checks, sifts := c.sifts } = c + { words := x }
          theorem Ratpoints.Sieve.Counters.words_mk_add (x y : UInt64) :
          { words := x + y } = { words := x } + { words := y }
          theorem Ratpoints.Sieve.Counters.arrays_mk_add (x y : UInt64) :
          { arrays := x + y } = { arrays := x } + { arrays := y }

          The counts of the tests of a candidate (Ratpoints.Sieve.accepted) of the numerators as over the denominator b, with the thunk checks of the third stage, each numerator counted in bits before its test, as the walk through the set bits of a word counts them (Ratpoints.Sieve.walkWord): bits the number of the numerators, coprime the number of those prime to b on the words of the C code (Ratpoints.Sieve.relprime), and checks the number of those that pass the third stage too, each as a UInt64, wrapping.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            @[simp]
            theorem Ratpoints.Sieve.testedCounts_append (b : Nat) (checks : Thunk (List CheckSpec)) (as bs : List Int) :
            testedCounts b checks (as ++ bs) = testedCounts b checks as + testedCounts b checks bs
            theorem Ratpoints.Sieve.snd_run_accepted (a : Int) (b : Nat) (checks : Thunk (List CheckSpec)) (cnt : Counters) :
            (accepted a b checks { words := cnt.words, arrays := cnt.arrays, bits := cnt.bits + 1, coprime := cnt.coprime, checks := cnt.checks, sifts := cnt.sifts }).run.snd = cnt + testedCounts b checks [a]

            The counts of the test of a candidate, with the count of the numerator in bits before it as the walk through the set bits of a word counts it (Ratpoints.Sieve.walkWord).

            theorem Ratpoints.Sieve.eq_add_testedCounts_of_eq_run_accepted {a : Int} {b : Nat} {checks : Thunk (List CheckSpec)} {ok : Bool} {c c' : Counters} (h : (ok, c') = (accepted a b checks { words := c.words, arrays := c.arrays, bits := c.bits + 1, coprime := c.coprime, checks := c.checks, sifts := c.sifts }).run) :
            c' = c + testedCounts b checks [a]

            The counters c' after the test of a candidate of a, with its count in bits before it, in the shape of the verification conditions of the walk through the set bits of a word.

            The exact check #

            @[simp]

            The map of the reversal keeps the y-coordinate.

            theorem Ratpoints.Sieve.filter_map_swapPoint (rev noY : Bool) (L : List (Int × Int × Int)) :
            List.filter (fun (p : Int × Int × Int) => !noY || decide (0 ≤ p.snd.fst)) (List.map (if rev = true then swapPoint else id) L) = List.map (if rev = true then swapPoint else id) (List.filter (fun (p : Int × Int × Int) => !noY || decide (0 ≤ p.snd.fst)) L)

            The map of the reversal and the test of RATPOINTS_NO_Y commute, since the map keeps the y-coordinate.

            The map of the reversal commutes with the replacement of y by 0, since it moves only x and z.

            theorem Ratpoints.Delivery.callMapped_eq_deliver {σ : Type} (process : Int → Int → Int → σ → Answer σ) {r : Delivery σ} (hr : r.quit = false) (rev : Bool) (a b y : Int) :
            callMapped process r rev a b y = deliver process r [(if rev = true then Sieve.swapPoint else id) (a, y, b)]

            One call of the callback with the point (a : y : b), mapped back after a reversal, on a delivery whose flag is clear, is the delivery of that point mapped by Ratpoints.Sieve.swapPoint when rev is set.

            The points that the exact check (Ratpoints.Sieve.checkPoint) of the numerator a over the denominator b delivers to a callback that does not stop the search, for the products w, the factor f and the flags fl: unless fl.noCheck, the points (a, y, b) and, for y ≠ 0, (a, -y, b) when the value v of Horner's rule in a on w, times f, is y ^ 2 with y ≥ 0 (Ratpoints.BruteForce.pointsAbove), the point with y < 0 left out when fl.noY is set; with fl.noCheck, the one survivor (a, 0, b); each mapped by Ratpoints.Sieve.swapPoint when the flag fl.reversed of the reversal is set.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              theorem Ratpoints.Sieve.checkPoint_eq_deliver {σ : Type} (process : Int → Int → Int → σ → Answer σ) (w : Thunk (List Int)) (d : Nat) (b : Int) (fl : CheckFlags) (a : Int) {r : Delivery σ} (hr : r.quit = false) :
              checkPoint process w d b fl a r = Delivery.deliver process r (checkPointList w.get (if d % 2 = 1 then b else 1) b fl a)

              The exact check on a delivery whose flag is clear delivers the points of Ratpoints.Sieve.checkPointList, the call with -y left out after a call that stops the search.

              The check of the numerator a over the denominator b with the flags fl: the points of Ratpoints.Sieve.checkPointList when a is prime to b, and none otherwise. With the flags RATPOINTS_NO_CHECK and RATPOINTS_NO_Y clear, it is the check of the reference (Ratpoints.Sieve.checkNumWith_of_noCheck_eq_false).

              Equations
              Instances For
                theorem Ratpoints.Sieve.checkNumWith_of_noCheck_eq_false {fl : CheckFlags} (hc : fl.noCheck = false) (w : List Int) (f b a : Int) :
                checkNumWith w f b fl a = List.filter (fun (p : Int × Int × Int) => !fl.noY || decide (0 ≤ p.snd.fst)) (checkNum w f b fl.reversed a)

                Without RATPOINTS_NO_CHECK, the check with the flags is the check of the reference with the flag of the reversal, without the points with y < 0 under RATPOINTS_NO_Y.

                Under RATPOINTS_NO_CHECK, the check with the flags gives the survivor (a, 0, b) of a numerator prime to b, mapped after a reversal.

                theorem Ratpoints.Sieve.checkNumWith_eq_map (w : List Int) (f b : Int) (fl : CheckFlags) (a : Int) :
                checkNumWith w f b fl a = List.map (if fl.reversed = true then swapPoint else id) (checkNumWith w f b { noCheck := fl.noCheck, noY := fl.noY } a)

                The check with the flags gives the points of the check without the flag of the reversal, mapped by Ratpoints.Sieve.swapPoint when it is set.

                theorem Ratpoints.Sieve.mem_checkNumWith_of_noCheck {fl : CheckFlags} (hc : fl.noCheck = true) {w : List Int} {f b a : Int} {q : Int × Int × Int} :
                q ∈ checkNumWith w f b fl a ↔ a.gcd b = 1 ∧ q = (if fl.reversed = true then swapPoint else id) (a, 0, b)
                theorem Ratpoints.Sieve.fst_eq_and_snd_snd_eq_of_mem_checkNumWith {w : List Int} {f b : Int} {fl : CheckFlags} (hr : fl.reversed = false) {a : Int} {q : Int × Int × Int} (hq : q ∈ checkNumWith w f b fl a) :
                q.fst = a ∧ q.snd.snd = b

                Without the flag of the reversal, the points of the check with the flags of the numerator a over b are (a, y, b).

                theorem Ratpoints.Sieve.map_checkNumWith_sublist (w : List Int) (f b : Int) (rev noY : Bool) (a : Int) :
                (List.map (fun (q : Int × Int × Int) => (q.fst, 0, q.snd.snd)) (checkNumWith w f b { reversed := rev, noY := true } a)).Sublist (checkNumWith w f b { reversed := rev, noCheck := true, noY := noY } a)

                Without RATPOINTS_NO_CHECK and with RATPOINTS_NO_Y, the check of a numerator a over b gives at most one point, the one with y ≥ 0; with y replaced by 0 it is the survivor that the check gives under RATPOINTS_NO_CHECK.

                def Ratpoints.Sieve.acceptedPoints (w : Thunk (List Int)) (d b : Nat) (fl : CheckFlags) (checks : Thunk (List CheckSpec)) (a : Int) :

                The points that the extraction delivers for the numerator a over the denominator b: those of the exact check (Ratpoints.Sieve.checkPointList, with the thunk w of the products, the degree d and the flags fl) when a passes the test of a candidate (Ratpoints.Sieve.accepted, with the thunk checks of the third stage), and none otherwise.

                Equations
                • One or more equations did not get rendered due to their size.
                Instances For
                  theorem Ratpoints.Sieve.acceptedPoints_eq_ite {es : List SieveEntry} (hes : ∀ (e : SieveEntry), e ∈ es → e.IsPrimeEntry) {a : Int} {b H : Nat} {checks : Thunk (List CheckSpec)} (hc : checks.get = fillChecks b H es (List.map (fun (e : SieveEntry) => magic e.p) es)) (w : Thunk (List Int)) (d : Nat) (fl : CheckFlags) (hb : 0 < b) (hb63 : b < 2 ^ 63) (ha : a.natAbs ≤ H) (hH : H < 2 ^ 63) :
                  acceptedPoints w d b fl checks a = if survives es b a = true then checkNumWith w.get (if d % 2 = 1 then ↑b else 1) (↑b) fl a else []

                  The points of Ratpoints.Sieve.acceptedPoints, the test of Ratpoints.Sieve.accepted followed by the exact check, are those of the check with the flags Ratpoints.Sieve.checkNumWith for a numerator a with |a| ≤ H < 2 ^ 63 that survives the sieve entries es of the third stage, of the shape of Ratpoints.Sieve.SieveEntry.IsPrimeEntry, and none for the others, for a denominator 0 < b < 2 ^ 63.

                  theorem Ratpoints.Sieve.checkPoint_eq_deliver_acceptedPoints {σ : Type} (process : Int → Int → Int → σ → Answer σ) (w : Thunk (List Int)) (d b : Nat) (fl : CheckFlags) {checks : Thunk (List CheckSpec)} {a : Int} {cnt : Counters} (h : (accepted a b checks cnt).run.fst = true) {r : Delivery σ} (hr : r.quit = false) :
                  checkPoint process w d (↑b) fl a r = Delivery.deliver process r (acceptedPoints w d b fl checks a)

                  The exact check of a numerator that passes the test of a candidate, on a delivery whose flag is clear, delivers the points of Ratpoints.Sieve.acceptedPoints.

                  theorem Ratpoints.Sieve.deliver_acceptedPoints_of_not_accepted {σ : Type} (process : Int → Int → Int → σ → Answer σ) (w : Thunk (List Int)) (d b : Nat) (fl : CheckFlags) {checks : Thunk (List CheckSpec)} {a : Int} {cnt : Counters} (h : ¬(accepted a b checks cnt).run.fst = true) (r : Delivery σ) :
                  Delivery.deliver process r (acceptedPoints w d b fl checks a) = r

                  A numerator that does not pass the test of a candidate has no points to deliver.

                  Without RATPOINTS_NO_CHECK, the checks with the flags of the numerators xs over b give the points of the brute-force reference, mapped by Ratpoints.Sieve.swapPoint after a reversal, without those with y < 0 under RATPOINTS_NO_Y.

                  The points at infinity #

                  The points that Ratpoints.Sieve.pointsAtInfinity delivers to a callback that does not stop the search, for the polynomial of degree d with the coefficient list c and the flags fl: when there are points at infinity, for odd d or c_d a square (Ratpoints.Setup.isSquare), with fl.noCheck or odd d the point (1, 0, 0), and otherwise (1, s, 0) for s = √c_d followed, unless fl.noY, by (1, -s, 0); each mapped by Ratpoints.Sieve.swapPoint to (0, y, 1) when the flag fl.reversed of the reversal is set.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem Ratpoints.Sieve.pointsAtInfinity_eq_deliver {σ : Type} (process : Int → Int → Int → σ → Answer σ) (c : List Int) (d : Nat) (fl : CheckFlags) {r : Delivery σ} (hr : r.quit = false) :
                    pointsAtInfinity process c d fl r = Delivery.deliver process r (pointsAtInfinityList c d fl)

                    The points at infinity on a delivery whose flag is clear deliver the points of Ratpoints.Sieve.pointsAtInfinityList, the call with -√c_d left out after a call that stops the search.

                    Without RATPOINTS_NO_CHECK, for odd d or c_d ≠ 0, the points at infinity delivered are those of the candidate (1, 0) with the value F(1, 0), which is c_d for even d and 0 for odd d, without the point with y < 0 under RATPOINTS_NO_Y, and mapped after a reversal. (For even d and c_d = 0, which the search refuses before, the point (1 : 0 : 0) is delivered twice, once under RATPOINTS_NO_Y.)

                    Under RATPOINTS_NO_CHECK, the points at infinity delivered are the one survivor (1, 0, 0), mapped after a reversal, when there are points at infinity.

                    The points at infinity are those without the flag of the reversal, mapped by Ratpoints.Sieve.swapPoint when it is set.

                    Without the flag of the reversal, the points at infinity that the search delivers have z = 0.

                    theorem Ratpoints.Sieve.map_pointsAtInfinityList (c : List Int) (d : Nat) (rev noY : Bool) :
                    List.map (fun (q : Int × Int × Int) => (q.fst, 0, q.snd.snd)) (pointsAtInfinityList c d { reversed := rev, noY := true }) = pointsAtInfinityList c d { reversed := rev, noCheck := true, noY := noY }

                    Without RATPOINTS_NO_CHECK and with RATPOINTS_NO_Y, the points at infinity, with y replaced by 0, are those under RATPOINTS_NO_CHECK.

                    The second stage #

                    The invariant of the loop of Ratpoints.Sieve.secondStage over the moduli specs and their reciprocals mgs on the bit array nums with the word number i, after the moduli pref, whose state is the bit array and the reciprocals still to come: before the loop has gone through all the moduli, these are the reciprocals after the first pref.length; and word κ of the bit array is word κ of nums and-ed with the row words of the moduli of pref.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      theorem Ratpoints.Sieve.SecondStageInvariant.next?_ne_none {nums v : Vector UInt64 rbaPack} {i : Int} {small : Bool} {specs pref suff : List SieveSpec} {s : SieveSpec} {mgs rest : List Nat} (pre : StageFits specs mgs small i (i + 1)) (hs : specs = pref ++ s :: suff) (h : SecondStageInvariant nums i specs mgs pref (v, rest)) :
                      theorem Ratpoints.Sieve.SecondStageInvariant.getElem!_eq {nums : Vector UInt64 rbaPack} {i : Int} {specs : List SieveSpec} {mgs : List Nat} {st : Vector UInt64 rbaPack × List Nat} (h : SecondStageInvariant nums i specs mgs specs st) {κ : Nat} (hκ : κ < rbaPack) :
                      st.fst[κ]! = andWords specs nums[κ]! i κ
                      theorem Ratpoints.Sieve.SecondStageInvariant.of_isZeroAt {nums v : Vector UInt64 rbaPack} {i : Int} {specs pref suff : List SieveSpec} {cur : SieveSpec} {mgs rest rest' : List Nat} (hs : specs = pref ++ cur :: suff) (h : SecondStageInvariant nums i specs mgs pref (v, rest)) (hz : isZeroAt v 0 = true) :
                      SecondStageInvariant nums i specs mgs specs (v, rest')

                      At the stop the bit array is zero, and so is its and with the rows of the other moduli.

                      theorem Ratpoints.Sieve.SecondStageInvariant.andBitArray {nums v : Vector UInt64 rbaPack} {i : Int} {small : Bool} {specs pref suff : List SieveSpec} {s : SieveSpec} {mgs rest rest' : List Nat} {mg : Nat} (pre : StageFits specs mgs small i (i + 1)) (hs : specs = pref ++ s :: suff) (h : SecondStageInvariant nums i specs mgs pref (v, rest)) (hnext : Std.Stream.next? rest = some (mg, rest')) :
                      SecondStageInvariant nums i specs mgs (pref ++ [s]) (Sieve.andBitArray v 0 s.row (if small = true then mulMod (i + ↑s.offset).toNat s.p mg else (modLong (i + ↑s.offset) ↑s.p).toNat), rest')

                      A step of the loop of Ratpoints.Sieve.secondStage: the bit array and-ed with bit array (i + offset) mod p of the row of the next modulus s, the index that the reduction by the reciprocal of the cursor gives under the test small (Ratpoints.Sieve.SieveSpec.Fits.ite_mulMod_modLong_eq_toNat_emod).

                      theorem Ratpoints.Sieve.secondStage_spec (specs : List SieveSpec) (mgs : List Nat) (small : Bool) (i : Int) (nums : Vector UInt64 rbaPack) :
                      ⦃ StageFits specs mgs small i (i + 1) ⦄ secondStage specs mgs small i nums ⦃ fun (r : Vector UInt64 rbaPack) => ∀ (κ : Nat), κ < rbaPack → r[κ]! = andWords specs nums[κ]! i κ ⦄

                      The stop when the bit array is zero loses nothing, since a zero bit array stays zero; the reciprocals run in step with the moduli and do not run out before them.

                      def Ratpoints.Sieve.SecondStageWordInvariant (x0 : UInt64) (i : Int) (κ : Nat) (specs : List SieveSpec) (mgs : List Nat) (pref : List SieveSpec) (st : UInt64 × List Nat) :

                      The invariant of the loop of Ratpoints.Sieve.secondStageWord over the moduli specs and their reciprocals mgs on word κ of the bit array with the word number i, from the word x0 on, after the moduli pref, whose state is the word and the reciprocals still to come: before the loop has gone through all the moduli, these are the reciprocals after the first pref.length; and the word is x0 and-ed with the row words of the moduli of pref.

                      Equations
                      Instances For
                        theorem Ratpoints.Sieve.SecondStageWordInvariant.and {x0 x : UInt64} {i : Int} {κ : Nat} (hκ : κ < rbaPack) {small : Bool} {specs pref suff : List SieveSpec} {s : SieveSpec} {mgs rest rest' : List Nat} {mg : Nat} (pre : StageFits specs mgs small i (i + 1)) (hs : specs = pref ++ s :: suff) (h : SecondStageWordInvariant x0 i κ specs mgs pref (x, rest)) (hnext : Std.Stream.next? rest = some (mg, rest')) :
                        SecondStageWordInvariant x0 i κ specs mgs (pref ++ [s]) (x &&& s.row[(rbaPack * if small = true then mulMod (i + ↑s.offset).toNat s.p mg else (modLong (i + ↑s.offset) ↑s.p).toNat) + κ]!, rest')

                        A step of the loop of Ratpoints.Sieve.secondStageWord, as for Ratpoints.Sieve.SecondStageInvariant.andBitArray.

                        theorem Ratpoints.Sieve.SecondStageWordInvariant.next?_ne_none {x0 x : UInt64} {i : Int} {κ : Nat} {small : Bool} {specs pref suff : List SieveSpec} {s : SieveSpec} {mgs rest : List Nat} (pre : StageFits specs mgs small i (i + 1)) (hs : specs = pref ++ s :: suff) (h : SecondStageWordInvariant x0 i κ specs mgs pref (x, rest)) :
                        theorem Ratpoints.Sieve.secondStageWordInvariant_nil (x0 : UInt64) (i : Int) (κ : Nat) (specs : List SieveSpec) (mgs : List Nat) :
                        theorem Ratpoints.Sieve.SecondStageWordInvariant.eq {x0 : UInt64} {i : Int} {κ : Nat} {specs : List SieveSpec} {mgs : List Nat} {st : UInt64 × List Nat} (h : SecondStageWordInvariant x0 i κ specs mgs specs st) :
                        st.fst = andWords specs x0 i κ
                        theorem Ratpoints.Sieve.SecondStageWordInvariant.of_eq_zero {x0 x : UInt64} {i : Int} {κ : Nat} {specs pref suff : List SieveSpec} {cur : SieveSpec} {mgs rest rest' : List Nat} (hs : specs = pref ++ cur :: suff) (h : SecondStageWordInvariant x0 i κ specs mgs pref (x, rest)) (hz : (x == 0) = true) :
                        SecondStageWordInvariant x0 i κ specs mgs specs (x, rest')

                        At the stop the word is zero, and so is its and with the rows of the other moduli.

                        theorem Ratpoints.Sieve.secondStageWord_spec (specs : List SieveSpec) (mgs : List Nat) (small : Bool) (i : Int) {κ : Nat} (hκ : κ < rbaPack) (x : UInt64) :
                        ⦃ StageFits specs mgs small i (i + 1) ⦄ secondStageWord specs mgs small i κ x ⦃ fun (r : UInt64) => r = andWords specs x i κ ⦄

                        The stop when the word is zero loses nothing, since a zero word stays zero; the reciprocals run in step with the moduli and do not run out before them.