Imports
Natural-number serializers for circuit builders
Circuit encodings use unary natural numbers. This module connects the
counter-oriented builder layer to the actual CircuitSym alphabet: one
machine serializes the length of an arbitrary finite input, and a second
construction maps the verified stream of indices 0, ..., n - 1 to the
corresponding concatenation of encNat blocks.
noncomputable sectionopen StateTransitionnamespace CLRS.Chapter34.Turing.PolyBuilderEncoding one input length
Finite control for the direct input-length serializer.
inductive LengthEncodingLabel
| start
| pop
| push
| halt
deriving DecidableEq, Fintype
Emit encNat input.length directly in the circuit alphabet. The
terminator is pushed first; every consumed input symbol then prepends one
argument mark.
def lengthEncodingProgram (Γ : Type) [Fintype Γ] : Program Γ CircuitSym where
Label := LengthEncodingLabel
main := .start
op
| .start => .pushOutput .endMark .pop
| .pop => .popInput .halt (fun _ => .push)
| .push => .pushOutput .argMark .pop
| .halt => .haltExact step count for direct length serialization.
def lengthEncodingSteps {Γ : Type} (input : List Γ) : Nat :=
2 * input.length + 3private def lengthEncodingCfg {Γ : Type} [Fintype Γ]
(label : LengthEncodingLabel) (buffer : Option Γ) (input : List Γ)
(output : List CircuitSym) : BuilderCfg (lengthEncodingProgram Γ) :=
{ initialCfg (lengthEncodingProgram Γ) input with
label := some label
buffer₁ := buffer
output := output }private theorem replicate_append_cons {α : Type} (value : α)
(count : Nat) (tail : List α) :
List.replicate count value ++ value :: tail =
value :: (List.replicate count value ++ tail) := by
induction count with
| zero => rfl
| succ count ih =>
simp only [List.replicate_succ, List.cons_append]
exact congrArg (List.cons value) ihExact pop/push loop equation from an arbitrary output suffix.
private theorem lengthEncoding_popPush_eval {Γ : Type} [Fintype Γ]
(buffer : Option Γ) (input : List Γ) (output : List CircuitSym) :
(flip Option.bind (step (lengthEncodingProgram Γ)))^[
2 * input.length + 1]
(some (lengthEncodingCfg .pop buffer input output)) =
some (lengthEncodingCfg .halt none []
(List.replicate input.length .argMark ++ output)) := by
induction input generalizing buffer output with
| nil => rfl
| cons symbol rest ih =>
rw [show 2 * (symbol :: rest).length + 1 =
(2 * rest.length + 1) + 1 + 1 by simp; omega,
Function.iterate_succ_apply, Function.iterate_succ_apply]
change
(flip Option.bind (step (lengthEncodingProgram Γ)))^[
2 * rest.length + 1]
(some (lengthEncodingCfg .pop (some symbol) rest
(.argMark :: output))) = _
simpa only [List.length_cons, List.replicate_succ,
replicate_append_cons, List.cons_append] using
ih (some symbol) (.argMark :: output)Canonical exact run of the input-length serializer.
def lengthEncoding_run {Γ : Type} [Fintype Γ] (input : List Γ) :
EvalsToInTime (step (lengthEncodingProgram Γ))
(initialCfg (lengthEncodingProgram Γ) input)
(some (haltCfg (lengthEncodingProgram Γ) (encNat input.length)))
(lengthEncodingSteps input) := by
have hstart : EvalsToInTime (step (lengthEncodingProgram Γ))
(initialCfg (lengthEncodingProgram Γ) input)
(some (lengthEncodingCfg .pop none input [.endMark])) 1 := by
refine ⟨⟨1, ?_⟩, le_rfl⟩
rfl
have hloop : EvalsToInTime (step (lengthEncodingProgram Γ))
(lengthEncodingCfg .pop none input [.endMark])
(some (lengthEncodingCfg .halt none []
(List.replicate input.length .argMark ++ [.endMark])))
(2 * input.length + 1) := by
exact ⟨⟨2 * input.length + 1,
lengthEncoding_popPush_eval none input [.endMark]⟩, le_rfl⟩
have hhalt : EvalsToInTime (step (lengthEncodingProgram Γ))
(lengthEncodingCfg .halt none []
(List.replicate input.length .argMark ++ [.endMark]))
(some (haltCfg (lengthEncodingProgram Γ)
(List.replicate input.length .argMark ++ [.endMark]))) 1 := by
refine ⟨⟨1, ?_⟩, le_rfl⟩
rfl
let throughLoop := EvalsToInTime.trans (step (lengthEncodingProgram Γ))
1 (2 * input.length + 1) _ _ _ hstart hloop
let full := EvalsToInTime.trans (step (lengthEncodingProgram Γ))
((2 * input.length + 1) + 1) 1 _ _ _ throughLoop hhalt
have hbound : 1 + ((2 * input.length + 1) + 1) =
lengthEncodingSteps input := by
simp [lengthEncodingSteps]
omega
rw [← hbound]
simpa [encNat] using fullIndependent output contract for exact input-length serialization.
theorem lengthEncoding_builderOutputs {Γ : Type} [Fintype Γ] :
BuilderOutputs (lengthEncodingProgram Γ)
(fun input => encNat input.length) lengthEncodingSteps := by
intro input
exact ⟨lengthEncoding_run input⟩Compiled TM2 output contract for exact input-length serialization.
theorem lengthEncoding_outputs {Γ : Type} [Fintype Γ] :
Outputs (lengthEncodingProgram Γ)
(fun input => encNat input.length) lengthEncodingSteps :=
Outputs.of_builder_run lengthEncoding_builderOutputsLinear runtime envelope for the direct serializer.
noncomputable def lengthEncoding_polyBound {Γ : Type} :
PolyBound (@lengthEncodingSteps Γ) where
polynomial := 2 * Polynomial.X + 3
bound input := by
simp [lengthEncodingSteps, Polynomial.eval_add, Polynomial.eval_mul,
Polynomial.eval_X]
Concrete polynomial-time TM2 computing encNat input.length.
noncomputable def lengthEncoding_computableInPolyTime
(Γ : Type) [Fintype Γ] :
_root_.Turing.TM2ComputableInPolyTime id id
(fun input : List Γ => encNat input.length) :=
ComputableInPolyTime (lengthEncodingProgram Γ)
(fun input => encNat input.length) lengthEncodingSteps
lengthEncoding_outputs lengthEncoding_polyBoundEncoding the complete index stream
Interpret the Boolean counter presentation in the circuit alphabet.
def circuitIndexSymbol : Bool → CircuitSym
| true => .argMark
| false => .endMarkSymbol-local Boolean-to-circuit mapping used by the verified bounded loop.
def circuitIndexBody : LoopBody Bool CircuitSym where
emit symbol := [circuitIndexSymbol symbol]
cost _ := 1
emit_length_le_cost _ := le_rfl
Concatenated circuit encodings of 0, ..., count - 1.
def circuitIndexStream (count : Nat) : List CircuitSym :=
(List.range count).flatMap encNatMapping the Boolean index stream gives exactly the canonical circuit index stream.
theorem circuitIndexStream_eq_map (count : Nat) :
circuitIndexStream count =
(unaryIndexStream count).map circuitIndexSymbol := by
symm
rw [unaryIndexStream, List.map_flatMap]
simp only [circuitIndexStream]
congr 1
funext index
simp [unaryIndexCode, circuitIndexSymbol, encNat]
The actual CircuitSym index stream is polynomial-time computable from a
unit clock.
noncomputable def circuitIndexStream_computableInPolyTime :
_root_.Turing.TM2ComputableInPolyTime id id
(fun input : List Unit => circuitIndexStream input.length) := by
let composed :=
_root_.Turing.TM2Comp.TM2ComputableInPolyTime.comp_scratch
unaryIndexStream_computableInPolyTime
(boundedLoop_computableInPolyTime circuitIndexBody)
have hsingleton (bits : List Bool) :
bits.flatMap (fun symbol => [circuitIndexSymbol symbol]) =
bits.map circuitIndexSymbol := by
induction bits with
| nil => rfl
| cons symbol rest ih => simp [ih]
have hfun :
(fun input : List Unit =>
(unaryIndexStream input.length).flatMap
(fun symbol => [circuitIndexSymbol symbol])) =
(fun input : List Unit => circuitIndexStream input.length) := by
funext input
rw [hsingleton, circuitIndexStream_eq_map]
simpa [Function.comp_def, circuitIndexBody, hfun] using
Classical.choice composedend CLRS.Chapter34.Turing.PolyBuilder