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 public import Mathlib.Tactic.Attr.Core public import Mathlib.Tactic.Push
set_option doc.verso true

Binary counter costs

Least-significant-bit-first increment changes an initial sequence of ones and the next zero. The number of ones is a potential that bounds the total changes under repeated increments. These are costs of the list algorithm; a Turing-machine bound additionally requires simulation.

Main definitions

  • increment: binary increment, permitting leading zeroes.

  • flips: the number of digits changed by an increment.

  • totalFlips: the cumulative digit changes starting at zero.

Main statements

  • flips_add_count_increment: the exact potential identity.

  • totalFlips_le: at most two changes per increment, amortized.

  • flips_bits_le_succ_size: the incremented number's binary size bounds all changed bits.

  • size_mono: increasing counter values have nondecreasing binary size.

Tags

binary counter, amortized complexity, potential

@[expose] public sectionnamespace Geb.BitTree.Counter

Increment a binary word whose least significant digit comes first.

def increment : List Bool List Bool := List.rec [true] fun b bs next if b then false :: next else true :: bs

Number of bit changes, including the final zero-to-one change.

def flips : List Bool := List.foldr (fun b n if b then n + 1 else 1) 1

Carry propagation resets an initial sequence of ones.

theorem increment_replicate_true_append (k : ) (bs : List Bool) : increment (List.replicate k true ++ bs) = List.replicate k false ++ increment bs := k:bs:List Boolincrement (List.replicate k true ++ bs) = List.replicate k false ++ increment bs k:bs:List Boolincrement (List.replicate Nat.zero true ++ bs) = List.replicate Nat.zero false ++ increment bsk:bs:List Bool (n : ), increment (List.replicate n true ++ bs) = List.replicate n false ++ increment bs increment (List.replicate n.succ true ++ bs) = List.replicate n.succ false ++ increment bs k:bs:List Boolincrement (List.replicate Nat.zero true ++ bs) = List.replicate Nat.zero false ++ increment bs All goals completed! 🐙 k:bs:List Bool (n : ), increment (List.replicate n true ++ bs) = List.replicate n false ++ increment bs increment (List.replicate n.succ true ++ bs) = List.replicate n.succ false ++ increment bs k✝:bs:List Boolk:ih:increment (List.replicate k true ++ bs) = List.replicate k false ++ increment bsincrement (List.replicate k.succ true ++ bs) = List.replicate k.succ false ++ increment bs All goals completed! 🐙

Every initial one contributes one bit change before the remaining increment.

theorem flips_replicate_true_append (k : ) (bs : List Bool) : flips (List.replicate k true ++ bs) = k + flips bs := k:bs:List Boolflips (List.replicate k true ++ bs) = k + flips bs k:bs:List Boolflips (List.replicate Nat.zero true ++ bs) = Nat.zero + flips bsk:bs:List Bool (n : ), flips (List.replicate n true ++ bs) = n + flips bs flips (List.replicate n.succ true ++ bs) = n.succ + flips bs k:bs:List Boolflips (List.replicate Nat.zero true ++ bs) = Nat.zero + flips bs All goals completed! 🐙 k:bs:List Bool (n : ), flips (List.replicate n true ++ bs) = n + flips bs flips (List.replicate n.succ true ++ bs) = n.succ + flips bs k✝:bs:List Boolk:ih:flips (List.replicate k true ++ bs) = k + flips bsflips (List.replicate k.succ true ++ bs) = k.succ + flips bs k✝:bs:List Boolk:ih:List.foldr (fun b n if b = true then n + 1 else 1) (List.foldr (fun b n if b = true then n + 1 else 1) 1 bs) (List.replicate k true) = k + List.foldr (fun b n if b = true then n + 1 else 1) 1 bsList.foldr (fun b n if b = true then n + 1 else 1) (List.foldr (fun b n if b = true then n + 1 else 1) 1 bs) (List.replicate k true) + 1 = k + 1 + List.foldr (fun b n if b = true then n + 1 else 1) 1 bs All goals completed! 🐙

Every increment changes at least one bit.

theorem flips_pos (bs : List Bool) : 0 < flips bs := bs:List Bool0 < flips bs bs:List Bool0 < flips []bs:List Bool (head : Bool) (tail : List Bool), 0 < flips tail 0 < flips (head :: tail) bs:List Bool0 < flips [] All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), 0 < flips tail 0 < flips (head :: tail) bs✝:List Boolb:Boolbs:List Boolih:0 < flips bs0 < flips (b :: bs) bs✝:List Boolbs:List Boolih:0 < flips bs0 < flips (false :: bs)bs✝:List Boolbs:List Boolih:0 < flips bs0 < flips (true :: bs) bs✝:List Boolbs:List Boolih:0 < flips bs0 < flips (false :: bs)bs✝:List Boolbs:List Boolih:0 < flips bs0 < flips (true :: bs) All goals completed! 🐙

Every bit strictly before the last changed position is one.

theorem getD_eq_true_of_lt_flips (bs : List Bool) (i : ) (h : i + 1 < flips bs) : bs[i]?.getD false = true := bs:List Booli:h:i + 1 < flips bsbs[i]?.getD false = true bs:List Bool (i : ), i + 1 < flips bs bs[i]?.getD false = true bs:List Bool (i : ), i + 1 < flips [] [][i]?.getD false = truebs:List Bool (head : Bool) (tail : List Bool), (∀ (i : ), i + 1 < flips tail tail[i]?.getD false = true) (i : ), i + 1 < flips (head :: tail) (head :: tail)[i]?.getD false = true bs:List Bool (i : ), i + 1 < flips [] [][i]?.getD false = true bs:List Booli:hi:i + 1 < flips [][][i]?.getD false = true bs:List Booli:hi:i + 1 < 1[][i]?.getD false = true All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), (∀ (i : ), i + 1 < flips tail tail[i]?.getD false = true) (i : ), i + 1 < flips (head :: tail) (head :: tail)[i]?.getD false = true bs✝:List Boolb:Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < flips (b :: bs)(b :: bs)[i]?.getD false = true bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < flips (false :: bs)(false :: bs)[i]?.getD false = truebs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < flips (true :: bs)(true :: bs)[i]?.getD false = true bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < flips (false :: bs)(false :: bs)[i]?.getD false = true bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < 1(false :: bs)[i]?.getD false = true All goals completed! 🐙 bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 < flips (true :: bs)(true :: bs)[i]?.getD false = true cases i with bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truehi:0 + 1 < flips (true :: bs)(true :: bs)[0]?.getD false = true All goals completed! 🐙 bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 + 1 < flips (true :: bs)(true :: bs)[i + 1]?.getD false = true bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 + 1 < flips (true :: bs)bs[i]?.getD false = true bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 + 1 < flips (true :: bs)i + 1 < flips bs bs✝:List Boolbs:List Boolih: (i : ), i + 1 < flips bs bs[i]?.getD false = truei:hi:i + 1 + 1 < flips bs + 1i + 1 < flips bs All goals completed! 🐙

The final changed position contains zero, counting blanks as zero.

theorem getD_last_flip (bs : List Bool) : bs[flips bs - 1]?.getD false = false := bs:List Boolbs[flips bs - 1]?.getD false = false bs:List Bool[][flips [] - 1]?.getD false = falsebs:List Bool (head : Bool) (tail : List Bool), tail[flips tail - 1]?.getD false = false (head :: tail)[flips (head :: tail) - 1]?.getD false = false bs:List Bool[][flips [] - 1]?.getD false = false All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), tail[flips tail - 1]?.getD false = false (head :: tail)[flips (head :: tail) - 1]?.getD false = false bs✝:List Boolb:Boolbs:List Boolih:bs[flips bs - 1]?.getD false = false(b :: bs)[flips (b :: bs) - 1]?.getD false = false bs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = false(false :: bs)[flips (false :: bs) - 1]?.getD false = falsebs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = false(true :: bs)[flips (true :: bs) - 1]?.getD false = false bs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = false(false :: bs)[flips (false :: bs) - 1]?.getD false = false All goals completed! 🐙 bs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = false(true :: bs)[flips (true :: bs) - 1]?.getD false = false bs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = falsehf:0 < flips bs(true :: bs)[flips (true :: bs) - 1]?.getD false = false bs✝:List Boolbs:List Boolih:bs[flips bs - 1]?.getD false = falsehf:0 < flips bshe:flips (true :: bs) - 1 = flips bs - 1 + 1(true :: bs)[flips (true :: bs) - 1]?.getD false = false All goals completed! 🐙

Increment resets the initial ones, sets the following zero, and preserves later bits.

theorem getD_increment (bs : List Bool) (i : ) : (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD false := bs:List Booli:(increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD false bs:List Bool (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD false bs:List Bool (i : ), (increment [])[i]?.getD false = if i + 1 < flips [] then false else if i + 1 = flips [] then true else [][i]?.getD falsebs:List Bool (head : Bool) (tail : List Bool), (∀ (i : ), (increment tail)[i]?.getD false = if i + 1 < flips tail then false else if i + 1 = flips tail then true else tail[i]?.getD false) (i : ), (increment (head :: tail))[i]?.getD false = if i + 1 < flips (head :: tail) then false else if i + 1 = flips (head :: tail) then true else (head :: tail)[i]?.getD false bs:List Bool (i : ), (increment [])[i]?.getD false = if i + 1 < flips [] then false else if i + 1 = flips [] then true else [][i]?.getD false bs:List Booli:(increment [])[i]?.getD false = if i + 1 < flips [] then false else if i + 1 = flips [] then true else [][i]?.getD false cases i with bs:List Bool(increment [])[0]?.getD false = if 0 + 1 < flips [] then false else if 0 + 1 = flips [] then true else [][0]?.getD false All goals completed! 🐙 bs:List Booli:(increment [])[i + 1]?.getD false = if i + 1 + 1 < flips [] then false else if i + 1 + 1 = flips [] then true else [][i + 1]?.getD false bs:List Booli:false = if i + 1 + 1 < 1 then false else if i + 1 + 1 = 1 then true else false All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), (∀ (i : ), (increment tail)[i]?.getD false = if i + 1 < flips tail then false else if i + 1 = flips tail then true else tail[i]?.getD false) (i : ), (increment (head :: tail))[i]?.getD false = if i + 1 < flips (head :: tail) then false else if i + 1 = flips (head :: tail) then true else (head :: tail)[i]?.getD false bs✝:List Boolb:Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (b :: bs))[i]?.getD false = if i + 1 < flips (b :: bs) then false else if i + 1 = flips (b :: bs) then true else (b :: bs)[i]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (false :: bs))[i]?.getD false = if i + 1 < flips (false :: bs) then false else if i + 1 = flips (false :: bs) then true else (false :: bs)[i]?.getD falsebs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (true :: bs))[i]?.getD false = if i + 1 < flips (true :: bs) then false else if i + 1 = flips (true :: bs) then true else (true :: bs)[i]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (false :: bs))[i]?.getD false = if i + 1 < flips (false :: bs) then false else if i + 1 = flips (false :: bs) then true else (false :: bs)[i]?.getD false cases i with bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD false(increment (false :: bs))[0]?.getD false = if 0 + 1 < flips (false :: bs) then false else if 0 + 1 = flips (false :: bs) then true else (false :: bs)[0]?.getD false All goals completed! 🐙 bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (false :: bs))[i + 1]?.getD false = if i + 1 + 1 < flips (false :: bs) then false else if i + 1 + 1 = flips (false :: bs) then true else (false :: bs)[i + 1]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:bs[i]?.getD false = if i + 1 + 1 < 1 then false else if i + 1 + 1 = 1 then true else bs[i]?.getD false All goals completed! 🐙 bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (true :: bs))[i]?.getD false = if i + 1 < flips (true :: bs) then false else if i + 1 = flips (true :: bs) then true else (true :: bs)[i]?.getD false cases i with bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD false(increment (true :: bs))[0]?.getD false = if 0 + 1 < flips (true :: bs) then false else if 0 + 1 = flips (true :: bs) then true else (true :: bs)[0]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsehf:0 < flips bs(increment (true :: bs))[0]?.getD false = if 0 + 1 < flips (true :: bs) then false else if 0 + 1 = flips (true :: bs) then true else (true :: bs)[0]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsehf:0 < flips bsfalse = if 1 < flips bs + 1 then false else if 1 = flips bs + 1 then true else true All goals completed! 🐙 bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment (true :: bs))[i + 1]?.getD false = if i + 1 + 1 < flips (true :: bs) then false else if i + 1 + 1 = flips (true :: bs) then true else (true :: bs)[i + 1]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:(increment bs)[i]?.getD false = if i + 1 + 1 < flips bs + 1 then false else if i + 1 + 1 = flips bs + 1 then true else bs[i]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:hlt:i + 1 + 1 < flips bs + 1 i + 1 < flips bs(increment bs)[i]?.getD false = if i + 1 + 1 < flips bs + 1 then false else if i + 1 + 1 = flips bs + 1 then true else bs[i]?.getD false bs✝:List Boolbs:List Boolih: (i : ), (increment bs)[i]?.getD false = if i + 1 < flips bs then false else if i + 1 = flips bs then true else bs[i]?.getD falsei:hlt:i + 1 + 1 < flips bs + 1 i + 1 < flips bsheq:i + 1 + 1 = flips bs + 1 i + 1 = flips bs(increment bs)[i]?.getD false = if i + 1 + 1 < flips bs + 1 then false else if i + 1 + 1 = flips bs + 1 then true else bs[i]?.getD false All goals completed! 🐙

Each increment consumes one unit of potential for every trailing one it resets.

theorem flips_add_count_increment (bs : List Bool) : flips bs + (increment bs).count true = bs.count true + 2 := bs:List Boolflips bs + List.count true (increment bs) = List.count true bs + 2 bs:List Boolflips [] + List.count true (increment []) = List.count true [] + 2bs:List Bool (head : Bool) (tail : List Bool), flips tail + List.count true (increment tail) = List.count true tail + 2 flips (head :: tail) + List.count true (increment (head :: tail)) = List.count true (head :: tail) + 2 bs:List Boolflips [] + List.count true (increment []) = List.count true [] + 2 All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), flips tail + List.count true (increment tail) = List.count true tail + 2 flips (head :: tail) + List.count true (increment (head :: tail)) = List.count true (head :: tail) + 2 bs✝:List Boolb:Boolbs:List Boolih:flips bs + List.count true (increment bs) = List.count true bs + 2flips (b :: bs) + List.count true (increment (b :: bs)) = List.count true (b :: bs) + 2 bs✝:List Boolbs:List Boolih:flips bs + List.count true (increment bs) = List.count true bs + 2flips (false :: bs) + List.count true (increment (false :: bs)) = List.count true (false :: bs) + 2bs✝:List Boolbs:List Boolih:flips bs + List.count true (increment bs) = List.count true bs + 2flips (true :: bs) + List.count true (increment (true :: bs)) = List.count true (true :: bs) + 2 bs✝:List Boolbs:List Boolih:flips bs + List.count true (increment bs) = List.count true bs + 2flips (false :: bs) + List.count true (increment (false :: bs)) = List.count true (false :: bs) + 2bs✝:List Boolbs:List Boolih:flips bs + List.count true (increment bs) = List.count true bs + 2flips (true :: bs) + List.count true (increment (true :: bs)) = List.count true (true :: bs) + 2 bs✝:List Boolbs:List Boolih:List.foldr (fun b n if b = true then n + 1 else 1) 1 bs + List.count true (List.rec [true] (fun b bs next if b = true then false :: next else true :: bs) bs) = List.count true bs + 2List.foldr (fun b n if b = true then n + 1 else 1) 1 bs + 1 + List.count true (List.rec [true] (fun b bs next if b = true then false :: next else true :: bs) bs) = List.count true bs + 1 + 2 bs✝:List Boolbs:List Boolih:List.foldr (fun b n if b = true then n + 1 else 1) 1 bs + List.count true (List.rec [true] (fun b bs next if b = true then false :: next else true :: bs) bs) = List.count true bs + 21 + (List.count true bs + 1) = List.count true bs + 2bs✝:List Boolbs:List Boolih:List.foldr (fun b n if b = true then n + 1 else 1) 1 bs + List.count true (List.rec [true] (fun b bs next if b = true then false :: next else true :: bs) bs) = List.count true bs + 2List.foldr (fun b n if b = true then n + 1 else 1) 1 bs + 1 + List.count true (List.rec [true] (fun b bs next if b = true then false :: next else true :: bs) bs) = List.count true bs + 1 + 2 All goals completed! 🐙

Binary increment agrees with successor on natural numbers.

theorem increment_bits (n : ) : increment n.bits = (n + 1).bits := n:increment n.bits = (n + 1).bits n:increment (Nat.bits 0) = (0 + 1).bitsn: (b : Bool) (n : ), (n = 0 b = true) increment n.bits = (n + 1).bits increment (Nat.bit b n).bits = (Nat.bit b n + 1).bits n:increment (Nat.bits 0) = (0 + 1).bits All goals completed! 🐙 n: (b : Bool) (n : ), (n = 0 b = true) increment n.bits = (n + 1).bits increment (Nat.bit b n).bits = (Nat.bit b n + 1).bits n:b:Boolk:hk:k = 0 b = trueih:increment k.bits = (k + 1).bitsincrement (Nat.bit b k).bits = (Nat.bit b k + 1).bits n:b:Boolk:hk:k = 0 b = trueih:increment k.bits = (k + 1).bitsincrement (b :: k.bits) = (Nat.bit b k + 1).bits n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 false = trueincrement (false :: k.bits) = (Nat.bit false k + 1).bitsn:k:ih:increment k.bits = (k + 1).bitshk:k = 0 true = trueincrement (true :: k.bits) = (Nat.bit true k + 1).bits n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 false = trueincrement (false :: k.bits) = (Nat.bit false k + 1).bits All goals completed! 🐙 n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 true = trueincrement (true :: k.bits) = (Nat.bit true k + 1).bits n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 true = truefalse :: increment k.bits = (Nat.bit true k + 1).bits n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 true = truefalse :: (k + 1).bits = (2 * k + true.toNat + 1).bits n:k:ih:increment k.bits = (k + 1).bitshk:k = 0 true = truehe:2 * k + true.toNat + 1 = 2 * (k + 1)false :: (k + 1).bits = (2 * k + true.toNat + 1).bits All goals completed! 🐙

Cumulative bit changes of increments from zero to the argument.

def totalFlips : := Nat.rec 0 fun n cost cost + flips n.bits

Total changes plus the final potential equal twice the number of increments.

theorem totalFlips_add_count (n : ) : totalFlips n + n.bits.count true = 2 * n := n:totalFlips n + List.count true n.bits = 2 * n n:totalFlips Nat.zero + List.count true Nat.zero.bits = 2 * Nat.zeron: (n : ), totalFlips n + List.count true n.bits = 2 * n totalFlips n.succ + List.count true n.succ.bits = 2 * n.succ n:totalFlips Nat.zero + List.count true Nat.zero.bits = 2 * Nat.zero All goals completed! 🐙 n: (n : ), totalFlips n + List.count true n.bits = 2 * n totalFlips n.succ + List.count true n.succ.bits = 2 * n.succ n:k:ih:totalFlips k + List.count true k.bits = 2 * ktotalFlips k.succ + List.count true k.succ.bits = 2 * k.succ n:k:ih:totalFlips k + List.count true k.bits = 2 * kh:flips k.bits + List.count true (increment k.bits) = List.count true k.bits + 2totalFlips k.succ + List.count true k.succ.bits = 2 * k.succ n:k:ih:totalFlips k + List.count true k.bits = 2 * kh:flips k.bits + List.count true (k + 1).bits = List.count true k.bits + 2totalFlips k.succ + List.count true k.succ.bits = 2 * k.succ n:k:ih:totalFlips k + List.count true k.bits = 2 * kh:flips k.bits + List.count true (k + 1).bits = List.count true k.bits + 2totalFlips k + flips k.bits + List.count true (k + 1).bits = 2 * (k + 1) All goals completed! 🐙

Binary increment changes at most two digits per increment, amortized.

theorem totalFlips_le (n : ) : totalFlips n 2 * n := n:totalFlips n 2 * n n:h:totalFlips n + List.count true n.bits = 2 * ntotalFlips n 2 * n All goals completed! 🐙

An increment visits no more than the represented digits and the first blank digit.

theorem flips_le_length (bs : List Bool) : flips bs bs.length + 1 := bs:List Boolflips bs bs.length + 1 bs:List Boolflips [] [].length + 1bs:List Bool (head : Bool) (tail : List Bool), flips tail tail.length + 1 flips (head :: tail) (head :: tail).length + 1 bs:List Boolflips [] [].length + 1 All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), flips tail tail.length + 1 flips (head :: tail) (head :: tail).length + 1 bs✝:List Boolb:Boolbs:List Boolih:flips bs bs.length + 1flips (b :: bs) (b :: bs).length + 1 bs✝:List Boolbs:List Boolih:flips bs bs.length + 1flips (false :: bs) (false :: bs).length + 1bs✝:List Boolbs:List Boolih:flips bs bs.length + 1flips (true :: bs) (true :: bs).length + 1 bs✝:List Boolbs:List Boolih:flips bs bs.length + 1flips (false :: bs) (false :: bs).length + 1bs✝:List Boolbs:List Boolih:flips bs bs.length + 1flips (true :: bs) (true :: bs).length + 1 All goals completed! 🐙

Every changed digit belongs to the resulting counter representation.

theorem flips_le_increment_length (bs : List Bool) : flips bs (increment bs).length := bs:List Boolflips bs (increment bs).length bs:List Boolflips [] (increment []).lengthbs:List Bool (head : Bool) (tail : List Bool), flips tail (increment tail).length flips (head :: tail) (increment (head :: tail)).length bs:List Boolflips [] (increment []).length All goals completed! 🐙 bs:List Bool (head : Bool) (tail : List Bool), flips tail (increment tail).length flips (head :: tail) (increment (head :: tail)).length bs✝:List Boolb:Boolbs:List Boolih:flips bs (increment bs).lengthflips (b :: bs) (increment (b :: bs)).length bs✝:List Boolbs:List Boolih:flips bs (increment bs).lengthflips (false :: bs) (increment (false :: bs)).lengthbs✝:List Boolbs:List Boolih:flips bs (increment bs).lengthflips (true :: bs) (increment (true :: bs)).length bs✝:List Boolbs:List Boolih:flips bs (increment bs).lengthflips (false :: bs) (increment (false :: bs)).lengthbs✝:List Boolbs:List Boolih:flips bs (increment bs).lengthflips (true :: bs) (increment (true :: bs)).length All goals completed! 🐙

The incremented number's binary size bounds all digits changed by the increment.

theorem flips_bits_le_succ_size (n : ) : flips n.bits (n + 1).size := n:flips n.bits (n + 1).size n:h:flips n.bits (increment n.bits).lengthflips n.bits (n + 1).size rwa [n:h:flips n.bits (n + 1).bits.lengthflips n.bits (n + 1).size n:h:flips n.bits (n + 1).sizeflips n.bits (n + 1).sizen:h:flips n.bits (n + 1).sizeflips n.bits (n + 1).size at h

A counter value has exactly its binary size in represented digits.

theorem length_bits (n : ) : n.bits.length = n.size := Nat.size_eq_bits_len n

An increment visits at most one more cell than the binary size of its argument.

theorem flips_bits_le (n : ) : flips n.bits n.size + 1 := n:flips n.bits n.size + 1 All goals completed! 🐙

A number below a power of two uses no more digits than that exponent.

theorem size_le_of_lt_pow (n w : ) (h : n < 2 ^ w) : n.size w := n:w:h:n < 2 ^ wn.size w n: (w : ), n < 2 ^ w n.size w n: (w : ), 0 < 2 ^ w Nat.size 0 wn: (b : Bool) (n : ), (n = 0 b = true) (∀ (w : ), n < 2 ^ w n.size w) (w : ), Nat.bit b n < 2 ^ w (Nat.bit b n).size w n: (w : ), 0 < 2 ^ w Nat.size 0 w n:w:a✝:0 < 2 ^ wNat.size 0 w All goals completed! 🐙 n: (b : Bool) (n : ), (n = 0 b = true) (∀ (w : ), n < 2 ^ w n.size w) (w : ), Nat.bit b n < 2 ^ w (Nat.bit b n).size w n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size ww:h:Nat.bit b k < 2 ^ w(Nat.bit b k).size w n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size ww:h:Nat.bit b k < 2 ^ whn:Nat.bit b k 0(Nat.bit b k).size w n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size ww:h:Nat.bit b k < 2 ^ whn:Nat.bit b k 0k.size.succ w cases w with n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size whn:Nat.bit b k 0h:Nat.bit b k < 2 ^ 0k.size.succ 0 n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size whn:Nat.bit b k 0h:Nat.bit b k < 1k.size.succ 0; All goals completed! 🐙 n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size whn:Nat.bit b k 0w:h:Nat.bit b k < 2 ^ (w + 1)k.size.succ w + 1 n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size whn:Nat.bit b k 0w:h:Nat.bit b k < 2 ^ (w + 1)hk':k < 2 ^ wk.size.succ w + 1 n:b:Boolk:hk:k = 0 b = trueih: (w : ), k < 2 ^ w k.size whn:Nat.bit b k 0w:h:Nat.bit b k < 2 ^ (w + 1)hk':k < 2 ^ whs:k.size wk.size.succ w + 1 All goals completed! 🐙

A number is smaller than the power of two above all its represented digits.

theorem lt_pow_size (n : ) : n < 2 ^ n.size := n:n < 2 ^ n.size n:0 < 2 ^ Nat.size 0n: (b : Bool) (n : ), (n = 0 b = true) n < 2 ^ n.size Nat.bit b n < 2 ^ (Nat.bit b n).size n:0 < 2 ^ Nat.size 0 All goals completed! 🐙 n: (b : Bool) (n : ), (n = 0 b = true) n < 2 ^ n.size Nat.bit b n < 2 ^ (Nat.bit b n).size n:b:Boolk:hk:k = 0 b = trueih:k < 2 ^ k.sizeNat.bit b k < 2 ^ (Nat.bit b k).size n:b:Boolk:hk:k = 0 b = trueih:k < 2 ^ k.sizehn:Nat.bit b k 0Nat.bit b k < 2 ^ (Nat.bit b k).size n:b:Boolk:hk:k = 0 b = trueih:k < 2 ^ k.sizehn:Nat.bit b k 02 * k + b.toNat < 2 ^ k.size * 2 n:k:ih:k < 2 ^ k.sizehk:k = 0 false = truehn:Nat.bit false k 02 * k + false.toNat < 2 ^ k.size * 2n:k:ih:k < 2 ^ k.sizehk:k = 0 true = truehn:Nat.bit true k 02 * k + true.toNat < 2 ^ k.size * 2 n:k:ih:k < 2 ^ k.sizehk:k = 0 false = truehn:Nat.bit false k 02 * k + false.toNat < 2 ^ k.size * 2n:k:ih:k < 2 ^ k.sizehk:k = 0 true = truehn:Nat.bit true k 02 * k + true.toNat < 2 ^ k.size * 2 n:k:ih:k < 2 ^ k.sizehk:k = 0 true = truehn:Nat.bit true k 02 * k + 1 < 2 ^ k.size * 2 n:k:ih:k < 2 ^ k.sizehk:k = 0 false = truehn:Nat.bit false k 02 * k + 0 < 2 ^ k.size * 2n:k:ih:k < 2 ^ k.sizehk:k = 0 true = truehn:Nat.bit true k 02 * k + 1 < 2 ^ k.size * 2 All goals completed! 🐙

Binary size is monotone in the represented natural number.

theorem size_mono {m n : } (h : m n) : m.size n.size := m:n:h:m nm.size n.size m:n:h:m nhn:n < 2 ^ n.sizem.size n.size exact size_le_of_lt_pow m n.size (m:n:h:m nhn:n < 2 ^ n.sizem < 2 ^ n.size All goals completed! 🐙)
end Geb.BitTree.Counter