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 Geb.Prototypes.Computability.BitTree.Elias.Execution public import Geb.Prototypes.Computability.BitTree.Elias.ScannerCorrect public import Cslib.Computability.Machines.Turing.MultiTape.TapeLemmas
set_option doc.verso true

Resource bounds for the Elias-length recognizer

Work space counts all visited cells, including blank cells and marked origins. The input tape is read-only and excluded from CSLib's work-space measure.

Main statements

  • computableInTimeAndSpace_validBool proves simultaneous quadratic time and linear space.

  • spaceUsed_le_of_headBound converts the four head intervals to a work-space bound.

Implementation notes

The machine consumes each input bit once. Binary countdowns sweep their entire fixed-width words, including leading zeros, between input reads. Length fields are kept in binary, so malformed inputs advertising enormous payloads still halt within the same polynomial bound.

Tags

Elias delta code, Turing machine, running time, work space

@[expose] public sectionnamespace Geb.BitTree.Elias.Machineopen Turing MultiTapeTM

Four heads confined to the same interval visit at most four times its number of cells.

theorem spaceUsed_le_of_headBound {input : List (Fin 3)} (cfg : Cfg 4 (Fin 3) Control input) (width t : ) (h : u t, HeadBound width (machine.configs cfg u)) : machine.spaceUsed cfg t 4 * (width + 1) := input:List (Fin 3)cfg:Cfg 4 (Fin 3) Control inputwidth:t:h: u t, HeadBound width (configs cfg u)spaceUsed cfg t 4 * (width + 1) input:List (Fin 3)cfg:Cfg 4 (Fin 3) Control inputwidth:t:h: u t, HeadBound width (configs cfg u)hsub: (i : Fin 4), visitedByTapeHead cfg t i Finset.image (fun n n) (Finset.range (width + 1))spaceUsed cfg t 4 * (width + 1) input:List (Fin 3)cfg:Cfg 4 (Fin 3) Control inputwidth:t:h: u t, HeadBound width (configs cfg u)hsub: (i : Fin 4), visitedByTapeHead cfg t i Finset.image (fun n n) (Finset.range (width + 1))hi: (i : Fin 4), spaceUsedByTape cfg t i width + 1spaceUsed cfg t 4 * (width + 1) calc machine.spaceUsed cfg t _i : Fin 4, (width + 1) := Finset.sum_le_sum (fun i _ hi i) _ = 4 * (width + 1) := input:List (Fin 3)cfg:Cfg 4 (Fin 3) Control inputwidth:t:h: u t, HeadBound width (configs cfg u)hsub: (i : Fin 4), visitedByTapeHead cfg t i Finset.image (fun n n) (Finset.range (width + 1))hi: (i : Fin 4), spaceUsedByTape cfg t i width + 1 _i, (width + 1) = 4 * (width + 1) All goals completed! 🐙

After all input bits, one final transition halts.

theorem halts_at (w : List Bool) : (machine.configs (machine.initCfg (w.map boolEmb)) (1 + runCost w + 1)).state = none := w:List Bool(configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)).state = none w:List Boolh:have cost := 1 + runCost (List.take w.length w); have a := account (List.take w.length w); configs (initCfg (List.map (⇑boolEmb) w)) cost = modelCfg (List.map (⇑boolEmb) w) w.length + 1, a.1 a.2.1 a.2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) cost = [] u cost, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)(configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)).state = none w:List Boolh:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = [] u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)(configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)).state = none w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []right✝: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)(configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)).state = none w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []right✝: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)(MultiTapeTM.step (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2)).state = none All goals completed! 🐙

The only output is the decision of the Elias tree decoder.

theorem outputString_eq (w : List Bool) : machine.outputString (machine.initCfg (w.map boolEmb)) (1 + runCost w + 1) = [boolEmb (Elias.validBool w)] := w:List Boolmachine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1) = [boolEmb (validBool w)] w:List Boolh:have cost := 1 + runCost (List.take w.length w); have a := account (List.take w.length w); configs (initCfg (List.map (⇑boolEmb) w)) cost = modelCfg (List.map (⇑boolEmb) w) w.length + 1, a.1 a.2.1 a.2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) cost = [] u cost, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1) = [boolEmb (validBool w)] w:List Boolh:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = [] u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1) = [boolEmb (validBool w)] w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2ho:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []right✝: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1) = [boolEmb (validBool w)] w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2ho:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []right✝: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)[] ++ (some (boolEmb (decide ((Scanner.scan w).1 = Scanner.Mode.done)))).toList = [boolEmb (validBool w)] w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2ho:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []right✝: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)[boolEmb (Scanner.validBool w)] = [boolEmb (validBool w)] All goals completed! 🐙

The final halting transition preserves the work-head interval.

theorem headBound_run (w : List Bool) : u 1 + runCost w + 1, HeadBound (w.length + 1) (machine.configs (machine.initCfg (w.map boolEmb)) u) := w:List Bool u 1 + runCost w + 1, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolh:have cost := 1 + runCost (List.take w.length w); have a := account (List.take w.length w); configs (initCfg (List.map (⇑boolEmb) w)) cost = modelCfg (List.map (⇑boolEmb) w) w.length + 1, a.1 a.2.1 a.2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) cost = [] u cost, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) u 1 + runCost w + 1, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolh:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2 machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = [] u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) u 1 + runCost w + 1, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) u 1 + runCost w + 1, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1he:u 1 + runCost wHeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1he:¬u 1 + runCost wHeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1he:u 1 + runCost wHeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) All goals completed! 🐙 w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1he:¬u 1 + runCost wHeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)u:hu:u 1 + runCost w + 1he:¬u 1 + runCost whu':u = 1 + runCost w + 1HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)hu:1 + runCost w + 1 1 + runCost w + 1he:¬1 + runCost w + 1 1 + runCost wHeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)hu:1 + runCost w + 1 1 + runCost w + 1he:¬1 + runCost w + 1 1 + runCost whlast:HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w))HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)hu:1 + runCost w + 1 1 + runCost w + 1he:¬1 + runCost w + 1 1 + runCost whlast:HeadBound (w.length + 1) (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2)HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w + 1)) w:List Boolhc:configs (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2left✝:machine.outputString (initCfg (List.map (⇑boolEmb) w)) (1 + runCost w) = []hh: u 1 + runCost w, HeadBound (w.length + 1) (configs (initCfg (List.map (⇑boolEmb) w)) u)hu:1 + runCost w + 1 1 + runCost w + 1he:¬1 + runCost w + 1 1 + runCost whlast:HeadBound (w.length + 1) (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2)HeadBound (w.length + 1) { state := none, inputPos := (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2).inputPos, workTapes := (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2).workTapes, workTapePos := (modelCfg (List.map (⇑boolEmb) w) w.length + 1, (account w).1 (account w).2.1 (account w).2.2).workTapePos } All goals completed! 🐙

The one-pass Elias recognizer has simultaneous quadratic-time and linear-space bounds.

theorem computableInTimeAndSpace_validBool : ComputableInTimeAndSpace (fun w : List Bool [Elias.validBool w]) (fun n 5 * n ^ 2 + 16 * n + 2) (fun n 4 * (n + 2)) := ComputableInTimeAndSpace (fun w [validBool w]) (fun n 5 * n ^ 2 + 16 * n + 2) fun n 4 * (n + 2) w:List Bool t' (fun n 5 * n ^ 2 + 16 * n + 2) w.length, s' (fun n 4 * (n + 2)) w.length, machine.ComputesInTimeAndSpace (List.map (⇑boolEmb) w) (List.map (⇑boolEmb) ((fun w [validBool w]) w)) t' s' w:List Bool1 + runCost w + 1 (fun n 5 * n ^ 2 + 16 * n + 2) w.length w:List Bool1 + runCost w + 1 5 * w.length ^ 2 + 16 * w.length + 2 w:List Boolh:runCost w 5 * w.length ^ 2 + 16 * w.length1 + runCost w + 1 5 * w.length ^ 2 + 16 * w.length + 2 All goals completed! 🐙
end Geb.BitTree.Elias.Machine