Documentation

Batteries.Data.Nat.Digits

Digits #

Conversions between natural numbers and big-endian or little-endian lists of digits in a given base. The digits are represented as elements of Fin base.

The definitions are simple specifications. They are replaced at runtime, using csimp, by divide-and-conquer implementations, which are subquadratic when combined with the subquadratic multiplication and division of Nat.

def Nat.ofFinDigits {base : Nat} (l : List (Fin base)) :

Construct a natural number from a big-endian list of digits in the given base:

ofFinDigits (base := 10) [2,3,4] = 234 -- 2*10^2 + 3*10^1 + 4*10^0
ofFinDigits (base := 2) [0,1,0,0] = 4 -- 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
ofFinDigits (base := b) [] = 0 -- any base, including "base 0" and "base 1"

There are no valid inputs other than [] in "base 0". In "base 1", the only valid digit is 0 and therefore ofFinDigits (base := 1) l = 0.

Equations
Instances For
    def Nat.ofFinDigitsRev {base : Nat} (l : List (Fin base)) :

    Construct a natural number from a little-endian list of digits in the given base:

    ofFinDigitsRev (base := 10) [4,3,2] = 234 -- 2*10^2 + 3*10^1 + 4*10^0
    ofFinDigitsRev (base := 2) [0,0,1,0] = 4 -- 0*2^3 + 1*2^2 + 0*2^1 + 0*2^0
    ofFinDigitsRev (base := b) [] = 0 -- any base, including "base 0" and "base 1"
    

    There are no valid inputs other than [] in "base 0". In "base 1", the only valid digit is 0 and therefore ofFinDigitsRev (base := 1) l = 0.

    Equations
    Instances For
      def Nat.toFinDigitsFixed (n base prec : Nat) [NeZero base] :
      List (Fin base)

      The prec least significant digits of n in the given base, listed in big-endian order.

      Only "base 0" is invalid, this is ensured by a NeZero base instance. In "base 1" the result is always a list of 0s with length prec.

      toFinDigitsFixed 123 10 3 = ([1,2,3] : List (Fin 10))
      toFinDigitsFixed 123 10 2 = ([2,3] : List (Fin 10))
      toFinDigitsFixed 4 2 4 = ([0,1,0,0] : List (Fin 2))
      toFinDigitsFixed 12345 1 5 = ([0,0,0,0,0] : List (Fin 1))
      
      Equations
      Instances For
        def Nat.toFinDigitsFixedRev (n base prec : Nat) [NeZero base] :
        List (Fin base)

        The prec least significant digits of n in the given base, listed in little-endian order.

        Only "base 0" is invalid, this is ensured by a NeZero base instance. In "base 1" the result is always a list of 0s with length prec.

        toFinDigitsFixedRev 123 10 3 = ([3,2,1] : List (Fin 10))
        toFinDigitsFixedRev 123 10 2 = ([3,2] : List (Fin 10))
        toFinDigitsFixedRev 4 2 4 = ([0,0,1,0] : List (Fin 2))
        toFinDigitsFixedRev 12345 1 5 = ([0,0,0,0,0] : List (Fin 1))
        
        Equations
        Instances For
          @[irreducible]
          def Nat.toFinDigits (n base : Nat) :
          List (Fin base)

          Big-endian list of digits of a natural number n in a given base.

          When n is zero, the result is the empty list. Otherwise, the most significant digit is nonzero. The base should be at least 2, the result is always the empty list in "base 0" and "base 1".

          toFinDigits 123 10 = ([1,2,3] : List (Fin 10))
          toFinDigits 4 2 = ([1,0,0] : List (Fin 2))
          toFinDigits 0 12345 = ([] : List (Fin 12345))
          
          Equations
          Instances For
            @[irreducible]
            def Nat.toFinDigitsRev (n base : Nat) :
            List (Fin base)

            Little-endian list of digits of a natural number n in a given base.

            When n is zero, the result is the empty list. Otherwise, the most significant digit is nonzero. The base should be at least 2, the result is always the empty list in "base 0" and "base 1".

            toFinDigitsRev 123 10 = ([3,2,1] : List (Fin 10))
            toFinDigitsRev 4 2 = ([0,0,1] : List (Fin 2))
            toFinDigitsRev 0 12345 = ([] : List (Fin 12345))
            
            Equations
            Instances For

              Lemmas #

              @[simp]
              theorem Nat.ofFinDigits_nil {base : Nat} :
              theorem Nat.ofFinDigits_append {base : Nat} {l₁ l₂ : List (Fin base)} :
              ofFinDigits (l₁ ++ l₂) = ofFinDigits l₁ * base ^ l₂.length + ofFinDigits l₂
              @[simp]
              theorem Nat.ofFinDigits_cons {base : Nat} {d : Fin base} {l : List (Fin base)} :
              ofFinDigits (d :: l) = ↑d * base ^ l.length + ofFinDigits l
              @[simp]
              theorem Nat.toFinDigitsFixed_zero {base n : Nat} [NeZero base] :
              @[simp]
              theorem Nat.toFinDigitsFixed_succ {base n prec : Nat} [NeZero base] :
              n.toFinDigitsFixed base (prec + 1) = (n / base).toFinDigitsFixed base prec ++ [Fin.ofNat base n]
              @[simp]
              theorem Nat.length_toFinDigitsFixed {base n prec : Nat} [NeZero base] :
              (n.toFinDigitsFixed base prec).length = prec
              @[simp]
              theorem Nat.ofFinDigits_toFinDigitsFixed {base n prec : Nat} [NeZero base] :
              ofFinDigits (n.toFinDigitsFixed base prec) = n % base ^ prec
              theorem Nat.toFinDigitsFixed_add {base n prec k : Nat} [NeZero base] :
              n.toFinDigitsFixed base (prec + k) = (n / base ^ k).toFinDigitsFixed base prec ++ (n % base ^ k).toFinDigitsFixed base k
              theorem Nat.toFinDigits_zero {base : Nat} :
              theorem Nat.toFinDigits_of_ne_zero {base n : Nat} (h : 2 ≤ base) [NeZero base] (hn : n ≠ 0) :
              n.toFinDigits base = (n / base).toFinDigits base ++ [Fin.ofNat base n]
              @[simp]
              theorem Nat.ofFinDigits_toFinDigits {base n : Nat} (h : 2 ≤ base) :
              theorem Nat.toFinDigits_eq_append {base k n : Nat} (h : 2 ≤ base) [NeZero base] (hk : base ^ k ≤ n) :
              n.toFinDigits base = (n / base ^ k).toFinDigits base ++ (n % base ^ k).toFinDigitsFixed base k
              theorem Nat.ofFinDigits_of_le_one {base : Nat} (h : base ≤ 1) {l : List (Fin base)} :

              In "base 0" and "base 1", the only valid digits are zeros and ofFinDigits is always 0.

              theorem Nat.toFinDigitsFixed_one {n prec : Nat} :

              In "base 1", toFinDigitsFixed is a list of zeros.

              theorem Nat.ofFinDigits_lt_pow {base : Nat} {l : List (Fin base)} :
              @[simp]
              theorem Nat.toFinDigitsFixed_ofFinDigits {base : Nat} [NeZero base] {l : List (Fin base)} :
              theorem Nat.toFinDigits_of_lt_two {base n : Nat} (h : base < 2) :

              In "base 0" and "base 1", toFinDigits is always the empty list.

              @[simp]
              theorem Nat.toFinDigits_eq_nil_iff {n base : Nat} :
              n.toFinDigits base = [] ↔ n = 0 ∨ base < 2
              theorem Nat.toFinDigits_head?_ne_zero {n base : Nat} (d : Fin base) :
              d ∈ (n.toFinDigits base).head? → ↑d ≠ 0

              The most significant digit of toFinDigits n base is nonzero.

              theorem Nat.toFinDigits_ofFinDigits {base : Nat} (h : 2 ≤ base) {l : List (Fin base)} (hl : ∀ (d : Fin base), d ∈ l.head? → ↑d ≠ 0) :

              Subquadratic implementations #

              The definitions and theorems in the Nat.Internal namespace implement the functions above at runtime via csimp. They are public only because csimp requires it. They are not intended as part of the public API and they may change without warning.

              Each implementation splits its input roughly in half and falls back to a simple loop on small inputs, where computing base ^ k and splitting would cost more than it saves. The cutoffs are 16 digits for ofFinDigits and toFinDigitsFixed, and a split size of at least 8 digits for toFinDigits. They were picked by judgment rather than tuned by benchmarks. Correctness does not depend on them.

              @[irreducible]
              def Nat.Internal.ofFinDigits {base : Nat} (l : List (Fin base)) :

              Divide-and-conquer implementation of Nat.ofFinDigits.

              Equations
              • One or more equations did not get rendered due to their size.
              Instances For
                def Nat.Internal.toFinDigitsFixed (n base prec : Nat) [NeZero base] :
                List (Fin base)

                Divide-and-conquer implementation of Nat.toFinDigitsFixed.

                Equations
                Instances For
                  def Nat.Internal.toFinDigits (n base : Nat) :
                  List (Fin base)

                  Divide-and-conquer implementation of Nat.toFinDigits.

                  Equations
                  Instances For