Imports
/- Copyright (c) 2026 Terence Rokop. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Terence Rokop -/ module public import Mathlib.Data.Nat.Size
set_option doc.verso true

Canonical positive binary words

Positive binary integers have a leading one. Removing that bit identifies positive integers with arbitrary finite bitstrings, read from most to least significant bit.

Main definitions

  • payload removes the leading one from a positive integer's binary representation.

  • fromPayload restores the implicit leading one and reads the remaining digits.

  • readFixed reads a fixed number of such remaining digits.

Main statements

  • fromPayload_payload and payload_fromPayload give the two inverse laws.

  • readFixed_eq_some characterizes a successful fixed-width read.

Tags

binary representation, prefix code, parsing

@[expose] public sectionnamespace Geb.BitTree.Elias

The digits after the leading one, from most to least significant.

def payload (n : ) : List Bool := n.bits.reverse.tail

Read a most-significant-first payload with an implicit leading one.

def fromPayload (bs : List Bool) : := bs.foldl (fun n b Nat.bit b n) 1

A positive binary integer begins with one in most-significant-first order.

theorem reverse_bits_cons (n : ) : n 0 bs, n.bits.reverse = true :: bs := n:n 0 bs, n.bits.reverse = true :: bs n:0 0 bs, (Nat.bits 0).reverse = true :: bsn: (b : Bool) (n : ), (n = 0 b = true) (n 0 bs, n.bits.reverse = true :: bs) Nat.bit b n 0 bs, (Nat.bit b n).bits.reverse = true :: bs n:0 0 bs, (Nat.bits 0).reverse = true :: bs n:h:0 0 bs, (Nat.bits 0).reverse = true :: bs All goals completed! 🐙 n: (b : Bool) (n : ), (n = 0 b = true) (n 0 bs, n.bits.reverse = true :: bs) Nat.bit b n 0 bs, (Nat.bit b n).bits.reverse = true :: bs n:b:Boolk:hk:k = 0 b = trueih:k 0 bs, k.bits.reverse = true :: bsa✝:Nat.bit b k 0 bs, (Nat.bit b k).bits.reverse = true :: bs n:b:Boolk:hk:k = 0 b = trueih:k 0 bs, k.bits.reverse = true :: bsa✝:Nat.bit b k 0 bs, k.bits.reverse ++ [b] = true :: bs cases k with n:b:Boolhk:0 = 0 b = trueih:0 0 bs, (Nat.bits 0).reverse = true :: bsa✝:Nat.bit b 0 0 bs, (Nat.bits 0).reverse ++ [b] = true :: bs n:b:Boolhk:0 = 0 b = trueih:0 0 bs, (Nat.bits 0).reverse = true :: bsa✝:Nat.bit b 0 0hb:b = true bs, (Nat.bits 0).reverse ++ [b] = true :: bs n:ih:0 0 bs, (Nat.bits 0).reverse = true :: bshk:0 = 0 true = truea✝:Nat.bit true 0 0 bs, (Nat.bits 0).reverse ++ [true] = true :: bs All goals completed! 🐙 n:b:Boolk:hk:k + 1 = 0 b = trueih:k + 1 0 bs, (k + 1).bits.reverse = true :: bsa✝:Nat.bit b (k + 1) 0 bs, (k + 1).bits.reverse ++ [b] = true :: bs n:b:Boolk:hk:k + 1 = 0 b = trueih:k + 1 0 bs, (k + 1).bits.reverse = true :: bsa✝:Nat.bit b (k + 1) 0bs:List Boolhbs:(k + 1).bits.reverse = true :: bs bs, (k + 1).bits.reverse ++ [b] = true :: bs exact bs ++ [b], n:b:Boolk:hk:k + 1 = 0 b = trueih:k + 1 0 bs, (k + 1).bits.reverse = true :: bsa✝:Nat.bit b (k + 1) 0bs:List Boolhbs:(k + 1).bits.reverse = true :: bs(k + 1).bits.reverse ++ [b] = true :: (bs ++ [b]) n:b:Boolk:hk:k + 1 = 0 b = trueih:k + 1 0 bs, (k + 1).bits.reverse = true :: bsa✝:Nat.bit b (k + 1) 0bs:List Boolhbs:(k + 1).bits.reverse = true :: bstrue :: bs ++ [b] = true :: (bs ++ [b]); All goals completed! 🐙

The leading one and payload reconstruct a positive integer's binary digits.

theorem reverse_bits_eq (n : ) (hn : n 0) : n.bits.reverse = true :: payload n := n:hn:n 0n.bits.reverse = true :: payload n n:hn:n 0bs:List Boolhbs:n.bits.reverse = true :: bsn.bits.reverse = true :: payload n All goals completed! 🐙

Reading the least-significant-first representation returns its original number.

theorem foldr_bits (n : ) : n.bits.foldr Nat.bit 0 = n := n:List.foldr Nat.bit 0 n.bits = n n:List.foldr Nat.bit 0 (Nat.bits 0) = 0n: (b : Bool) (n : ), (n = 0 b = true) List.foldr Nat.bit 0 n.bits = n List.foldr Nat.bit 0 (Nat.bit b n).bits = Nat.bit b n n:List.foldr Nat.bit 0 (Nat.bits 0) = 0 All goals completed! 🐙 n: (b : Bool) (n : ), (n = 0 b = true) List.foldr Nat.bit 0 n.bits = n List.foldr Nat.bit 0 (Nat.bit b n).bits = Nat.bit b n n:b:Boolk:hk:k = 0 b = trueih:List.foldr Nat.bit 0 k.bits = kList.foldr Nat.bit 0 (Nat.bit b k).bits = Nat.bit b k All goals completed! 🐙

Restoring the implicit leading one recovers the positive integer.

theorem fromPayload_payload (n : ) (hn : n 0) : fromPayload (payload n) = n := n:hn:n 0fromPayload (payload n) = n n:hn:n 0h:List.foldl (fun n b Nat.bit b n) 0 n.bits.reverse = nfromPayload (payload n) = n n:hn:n 0h:List.foldl (fun n b Nat.bit b n) 0 (true :: payload n) = nfromPayload (payload n) = n All goals completed! 🐙

Appending a binary digit preserves positivity.

theorem bit_pos (b : Bool) (n : ) (hn : 0 < n) : 0 < Nat.bit b n := b:Booln:hn:0 < n0 < Nat.bit b n b:Booln:hn:0 < n0 < 2 * n + b.toNat All goals completed! 🐙

Appending digits preserves positivity and extends the canonical binary representation.

theorem foldl_bits (bs : List Bool) : n, 0 < n 0 < bs.foldl (fun n b Nat.bit b n) n (bs.foldl (fun n b Nat.bit b n) n).bits = bs.reverse ++ n.bits := List.rec (fun n hn hn, rfl) (fun b bs ih n hn bs✝:List Boolb:Boolbs:List Boolih: (n : ), 0 < n 0 < List.foldl (fun n b Nat.bit b n) n bs (List.foldl (fun n b Nat.bit b n) n bs).bits = bs.reverse ++ n.bitsn:hn:0 < n0 < List.foldl (fun n b Nat.bit b n) n (b :: bs) (List.foldl (fun n b Nat.bit b n) n (b :: bs)).bits = (b :: bs).reverse ++ n.bits bs✝:List Boolb:Boolbs:List Boolih: (n : ), 0 < n 0 < List.foldl (fun n b Nat.bit b n) n bs (List.foldl (fun n b Nat.bit b n) n bs).bits = bs.reverse ++ n.bitsn:hn:0 < nhp:0 < List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bshe:(List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bs).bits = bs.reverse ++ (Nat.bit b n).bits0 < List.foldl (fun n b Nat.bit b n) n (b :: bs) (List.foldl (fun n b Nat.bit b n) n (b :: bs)).bits = (b :: bs).reverse ++ n.bits bs✝:List Boolb:Boolbs:List Boolih: (n : ), 0 < n 0 < List.foldl (fun n b Nat.bit b n) n bs (List.foldl (fun n b Nat.bit b n) n bs).bits = bs.reverse ++ n.bitsn:hn:0 < nhp:0 < List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bshe:(List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bs).bits = bs.reverse ++ (Nat.bit b n).bits(List.foldl (fun n b Nat.bit b n) n (b :: bs)).bits = (b :: bs).reverse ++ n.bits bs✝:List Boolb:Boolbs:List Boolih: (n : ), 0 < n 0 < List.foldl (fun n b Nat.bit b n) n bs (List.foldl (fun n b Nat.bit b n) n bs).bits = bs.reverse ++ n.bitsn:hn:0 < nhp:0 < List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bshe:(List.foldl (fun n b Nat.bit b n) (Nat.bit b n) bs).bits = bs.reverse ++ (Nat.bit b n).bitsbs.reverse ++ b :: n.bits = bs.reverse ++ [b] ++ n.bits All goals completed! 🐙) bs

Restoring the leading one always gives a positive number.

theorem fromPayload_pos (bs : List Bool) : 0 < fromPayload bs := (foldl_bits bs 1 (bs:List Bool0 < 1 All goals completed! 🐙)).1

The reconstructed number has exactly the prescribed digits after its leading one.

theorem payload_fromPayload (bs : List Bool) : payload (fromPayload bs) = bs := bs:List Boolpayload (fromPayload bs) = bs bs:List Boolhe:(List.foldl (fun n b Nat.bit b n) 1 bs).bits = bs.reverse ++ Nat.bits 1payload (fromPayload bs) = bs All goals completed! 🐙

A reconstructed payload has one extra bit for its leading one.

theorem size_fromPayload (bs : List Bool) : (fromPayload bs).size = bs.length + 1 := bs:List Bool(fromPayload bs).size = bs.length + 1 bs:List Bool(fromPayload bs).bits.length = bs.length + 1 bs:List Bool(List.foldl (fun n b Nat.bit b n) 1 bs).bits.length = bs.length + 1 bs:List Boolbs.length + [true].length = bs.length + 1 All goals completed! 🐙

Dropping the leading bit subtracts one from the binary size.

theorem length_payload (n : ) : (payload n).length = n.size - 1 := n:(payload n).length = n.size - 1 All goals completed! 🐙

Positive numbers have positive binary size.

theorem size_pos (n : ) (hn : n 0) : 0 < n.size := n:hn:n 00 < n.size n:hn:n 0he:(fromPayload (payload n)).size = (payload n).length + 10 < n.size n:hn:n 0he:n.size = (payload n).length + 10 < n.size All goals completed! 🐙

Read a fixed-width payload, retaining the unconsumed suffix.

def readFixed (k : ) (w : List Bool) : Option ( × List Bool) := if k w.length then some (fromPayload (w.take k), w.drop k) else none

Reading exactly a payload's length recovers its value and leaves the suffix untouched.

theorem readFixed_append (bs rest : List Bool) : readFixed bs.length (bs ++ rest) = some (fromPayload bs, rest) := bs:List Boolrest:List BoolreadFixed bs.length (bs ++ rest) = some (fromPayload bs, rest) All goals completed! 🐙

A successful fixed-width read is precisely a canonical payload followed by its suffix.

theorem readFixed_eq_some (k : ) (w : List Bool) (n : ) (rest : List Bool) (h : readFixed k w = some (n, rest)) : n 0 n.size = k + 1 w = payload n ++ rest := k:w:List Booln:rest:List Boolh:readFixed k w = some (n, rest)n 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolh:(if k w.length then some (fromPayload (List.take k w), List.drop k w) else none) = some (n, rest)n 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolh✝:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)n 0 n.size = k + 1 w = payload n ++ restk:w:List Booln:rest:List Boolh✝:¬k w.lengthh:none = some (n, rest)n 0 n.size = k + 1 w = payload n ++ rest next hk k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)n 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)n 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nn 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restn 0 n.size = k + 1 w = payload n ++ rest k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restn 0k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restn.size = k + 1k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restw = payload n ++ rest k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restn 0 k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = resthp:0 < fromPayload (List.take k w)n 0 All goals completed! 🐙 k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restn.size = k + 1 All goals completed! 🐙 k:w:List Booln:rest:List Boolhk:k w.lengthh:some (fromPayload (List.take k w), List.drop k w) = some (n, rest)he:(fromPayload (List.take k w), List.drop k w) = (n, rest)hn:fromPayload (List.take k w) = nhr:List.drop k w = restw = payload n ++ rest All goals completed! 🐙 next k:w:List Booln:rest:List Boolh✝:¬k w.lengthh:none = some (n, rest)n 0 n.size = k + 1 w = payload n ++ rest All goals completed! 🐙
end Geb.BitTree.Elias