Imports
import Mathlib.Tactic.DeriveFintype
import Mathlib.TacticDelimiter-bearing unary runtime frames
The Ch34 validity family reuses three local unary registers for every gate
serializer. Runtime indices that must survive between primitive invocations
therefore live in a symbol-stack frame. A separator is essential: a plain
Unit stack cannot distinguish adjacent unary values, including zero.
namespace CLRS.Chapter34.Turing.PolyBuilderFinite alphabet for a sequence of delimiter-separated unary naturals.
inductive UnaryFrameSym
| tick
| separator
| frameEnd
deriving DecidableEq, Fintype, ReprOne self-delimiting unary natural.
def encodeUnaryFrameBlock (value : Nat) : List UnaryFrameSym :=
List.replicate value .tick ++ [.separator]Concatenated runtime frame. Zero is represented by a bare separator.
def encodeUnaryFrame (values : List Nat) : List UnaryFrameSym :=
values.flatMap encodeUnaryFrameBlockAccumulating parser for a delimiter-bearing unary frame. An unterminated final block is rejected.
def decodeUnaryFrameAux : Nat → List UnaryFrameSym → Option (List Nat)
| 0, [] => some []
| _ + 1, [] => none
| count, .tick :: rest => decodeUnaryFrameAux (count + 1) rest
| count, .separator :: rest =>
(count :: ·) <$> decodeUnaryFrameAux 0 rest
| _, .frameEnd :: _ => noneDecode a complete runtime frame.
def decodeUnaryFrame (frame : List UnaryFrameSym) : Option (List Nat) :=
decodeUnaryFrameAux 0 frame
private theorem decodeUnaryFrameAux_ticks (count value : Nat)
(rest : List UnaryFrameSym) :
decodeUnaryFrameAux count
(List.replicate value .tick ++ rest) =
decodeUnaryFrameAux (count + value) rest := by
induction value generalizing count with
| zero => simp
| succ value ih =>
simp only [List.replicate_succ, List.cons_append,
decodeUnaryFrameAux]
rw [ih]
simp only [Nat.add_assoc]
rw [Nat.add_comm 1 value]
private theorem decodeUnaryFrameAux_block (value : Nat)
(rest : List UnaryFrameSym) :
decodeUnaryFrameAux 0 (encodeUnaryFrameBlock value ++ rest) =
(value :: ·) <$> decodeUnaryFrameAux 0 rest := by
simp only [encodeUnaryFrameBlock, List.append_assoc,
List.cons_append, List.nil_append]
rw [decodeUnaryFrameAux_ticks]
simp only [Nat.zero_add]
cases value <;> rflEncoding followed by decoding returns every runtime index exactly, including empty frames and zero-valued fields.
@[simp] theorem decodeUnaryFrame_encode (values : List Nat) :
decodeUnaryFrame (encodeUnaryFrame values) = some values := by
induction values with
| nil => rfl
| cons value values ih =>
change decodeUnaryFrameAux 0
(encodeUnaryFrameBlock value ++ encodeUnaryFrame values) = _
rw [decodeUnaryFrameAux_block]
change (value :: ·) <$> decodeUnaryFrame
(encodeUnaryFrame values) = some (value :: values)
rw [ih]
rflExact frame size: one tick per unary unit and one separator per field.
@[simp] theorem encodeUnaryFrame_length (values : List Nat) :
(encodeUnaryFrame values).length =
(values.map fun value => value + 1).sum := by
induction values with
| nil => rfl
| cons value values ih =>
change (encodeUnaryFrameBlock value ++ encodeUnaryFrame values).length = _
rw [List.length_append, ih]
simp [encodeUnaryFrameBlock]Runtime frames are unambiguous.
theorem encodeUnaryFrame_injective : Function.Injective encodeUnaryFrame := by
intro left right hframe
have hdecode := congrArg decodeUnaryFrame hframe
simpa using hdecodeend CLRS.Chapter34.Turing.PolyBuilder