Documentation

MIPRE.TM.Code.Encoding.Nat

A self-delimiting binary code for natural numbers #

The prefix-free code used by the machine-description format (planning/tm-infrastructure.md, Milestone C, normative):

encodeNat n = 1^L 0 d₀ … d_{L-1}

where d₀ … d_{L-1} are the little-endian binary digits of n (Turing.natToBits; canonical: the empty string for 0, and the last digit of a nonzero number is true) and L is their count. So encodeNat 0 = [false], and in general (encodeNat n).length = 2·L + 1 with L = ⌈log₂ (n+1)⌉, characterized here without Nat.log2 by lt_two_pow_natToBits and natToBits_length_le.

The parser parseNat accepts only canonical digit strings (a digit block ending in false is rejected), which gives genuine canonicality: parseNat_sound says every accepted prefix is encodeNat of the parsed value. Together with the prefix property parseNat_encodeNat, all downstream codec soundness proofs are compositional (decision D11).

Everything is structurally recursive — natToBits runs on an explicit fuel, with a fuel-irrelevance lemma — so the kernel can evaluate the whole codec and tests can be by decide (decision D10).

Little-endian binary digits #

Little-endian binary digits, structurally recursive in an explicit fuel (so that the kernel can evaluate it); use Turing.natToBits, which instantiates the fuel.

Equations
Instances For

    The little-endian binary digits of a natural number: [] for 0; the last digit of a nonzero number is true.

    Equations
    Instances For

      The value of a little-endian digit string.

      Equations
      Instances For
        theorem Turing.natToBitsAux_congr {f₁ f₂ n : } (h₁ : n f₁) (h₂ : n f₂) :

        The digits do not depend on the fuel, as long as there is enough of it.

        theorem Turing.natToBits_succ (n : ) :
        natToBits (n + 1) = ((n + 1) % 2 == 1) :: natToBits ((n + 1) / 2)
        @[simp]
        theorem Turing.bitsToNat_cons (b : Bool) (l : List Bool) :
        bitsToNat (b :: l) = 2 * bitsToNat l + if b = true then 1 else 0
        theorem Turing.natToBits_two_mul {m : } (hm : 0 < m) :

        The digits of 2·m (for m > 0): a false in front of the digits of m.

        The digits of 2·m + 1: a true in front of the digits of m.

        @[simp]

        Digits round-trip: the value of the digits of n is n.

        Canonicality: no digit string produced by natToBits ends in false.

        A canonical nonempty digit string has positive value.

        Digits round-trip the other way: on canonical strings, natToBitsbitsToNat is the identity.

        The length of the digit string #

        natToBits n has enough digits for n.

        theorem Turing.natToBits_length_le {n k : } :
        n < 2 ^ k(natToBits n).length k

        natToBits n has no more digits than any binary bound on n.

        The digit count is monotone.

        The self-delimiting code #

        The self-delimiting code of a natural number: the digit count in unary, a false separator, then the digits.

        Equations
        Instances For

          Split a maximal run of leading trues.

          Equations
          Instances For

            Parse one self-delimiting natural number; rejects non-canonical digit strings.

            Equations
            • One or more equations did not get rendered due to their size.
            Instances For
              @[simp]
              theorem Turing.parseNat_encodeNat (n : ) (rest : List Bool) :
              parseNat (encodeNat n ++ rest) = some (n, rest)

              Prefix property: parseNat consumes exactly encodeNat n and returns the rest.

              theorem Turing.parseNat_sound {s rest : List Bool} {n : } (h : parseNat s = some (n, rest)) :
              s = encodeNat n ++ rest

              Soundness: every accepted prefix is the canonical encoding of the parsed value.

              theorem Turing.encodeNat_length_le {n k : } (h : n < 2 ^ k) :
              (encodeNat n).length 2 * k + 1

              The code of n < 2^k takes at most 2k + 1 bits.

              The code length is monotone.