CSG → LBA (Kuroda): the simulating machine and its single-step semantics #
This file builds the backward-simulating LBA kMachine g₀ for a non-contracting grammar g₀
with finitely many nonterminals, and develops all the shared infrastructure used by both
halves of the language equality:
- the work alphabet (
KWork/KGamma/KCell), states (KState), transition (kTransition) and machine (kMachine); - decoding the work track to a sentential form (
formW,formOf) and its list lemmas; - the single-step "echo" glue (
kStep_echo_*), the marked-tape sweeps (gotoLeft_reaches,check_sweep,accept_from_S) and the canonical cellmkCell; - the initial conversion sweep (
cAt,init_reaches).
The completeness and soundness arguments live in CSGToLBA/Completeness.lean and
CSGToLBA/Soundness.lean.
References #
- Kuroda, S.-Y. (1964), "Classes of languages and linear-bounded automata".
- Hopcroft, Motwani, Ullman, Introduction to Automata Theory, Languages, and Computation, Chapter 9.
The grammar-symbol alphabet is finite whenever both the terminal and nonterminal alphabets are.
Equations
The simulating machine #
We build a backward (reductive) simulator. On input w the tape starts with the |w|
input cells some (Sum.inl wᵢ); the machine first converts them to work cells
some (Sum.inr (isLeftEnd, isRightEnd, workSym)), where each workSym is a grammar symbol
(initially the terminal wᵢ) or the blank # (none). The boundary bits are set during the
conversion sweep: cell 0 is the start (the head begins there), and the right end is detected
the moment the rightward sweep re-reads an already-converted cell (the clamp at the last cell).
It then nondeterministically replays a derivation in reverse: each grammar rule
input_L ++ [N] ++ input_R → output_string is applied as output_string ↦ input_L ++ [N] ++ input_R, padding the freed cells with #. Symbols are kept contiguous by bubbling blanks
past symbols (a length-preserving swap of adjacent work cells). The machine accepts when the
non-blank work symbols spell exactly [S] (the start symbol), verified by a sweep between the
boundary markers.
A bound on rule lengths: at least every rule's output length.
Equations
- KurodaConstruction.ruleBound g₀ = List.foldr max 0 (List.map (fun (r : grule T g₀.nt) => r.output_string.length) g₀.rules)
Instances For
The work symbol stored in a cell: a grammar symbol, or the blank # (none).
Equations
- KurodaConstruction.KWork g₀ = Option (symbol T g₀.nt)
Instances For
The work-cell alphabet Γ: (isLeftEnd, isRightEnd, workSymbol).
Equations
Instances For
Control states of the backward simulator.
- init0
{T : Type}
{g₀ : grammar T}
: KState g₀
Convert cell
0(the known left end): markisLeftEnd, keep the terminal. - initSweep
{T : Type}
{g₀ : grammar T}
: KState g₀
Convert subsequent cells left-to-right; detect the right end on a clamp.
- sim
{T : Type}
{g₀ : grammar T}
: KState g₀
Roaming simulation state: move freely, or start applying a rule / the accept check.
- applyRule
{T : Type}
{g₀ : grammar T}
(r : Fin g₀.rules.length)
(k : Fin (ruleBound g₀ + 1))
: KState g₀
Applying the
r-th rule backward in a single left-to-right pass: skip blanks, match thek-th symbol ofoutput_string, writing the replacement (patList[k]ifk < |patList|, else blank) into that cell in place. - gotoLeft
{T : Type}
{g₀ : grammar T}
: KState g₀
Go to the left end (marked) to begin the accept check.
- check
{T : Type}
{g₀ : grammar T}
(seen : Bool)
: KState g₀
Accept-check sweep;
seenrecords whether the unique start symbol was passed. - accept
{T : Type}
{g₀ : grammar T}
: KState g₀
The (unique) accepting state.
Instances For
Equations
- One or more equations did not get rendered due to their size.
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 KurodaConstruction.KState.init0 = isTrue ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.init0 KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep KurodaConstruction.KState.initSweep = isTrue ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.initSweep KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim KurodaConstruction.KState.sim = isTrue ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.sim KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.applyRule r k) KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft KurodaConstruction.KState.gotoLeft = isTrue ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.gotoLeft KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check a) (KurodaConstruction.KState.check b) = if h : a = b then h ▸ isTrue ⋯ else isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq (KurodaConstruction.KState.check seen) KurodaConstruction.KState.accept = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept KurodaConstruction.KState.init0 = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept KurodaConstruction.KState.initSweep = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept KurodaConstruction.KState.sim = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept (KurodaConstruction.KState.applyRule r k) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept KurodaConstruction.KState.gotoLeft = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept (KurodaConstruction.KState.check seen) = isFalse ⋯
- KurodaConstruction.instDecidableEqKState.decEq KurodaConstruction.KState.accept KurodaConstruction.KState.accept = isTrue ⋯
Instances For
A tape cell: an input symbol some (Sum.inl t), a work cell some (Sum.inr γ), or blank.
Equations
Instances For
The reverse-rule replacement string for rule r: input_L ++ [N] ++ input_R
(what output_string is rewritten back to).
Equations
- KurodaConstruction.patList g₀ r = r.input_L ++ [symbol.nonterminal r.input_N] ++ r.input_R
Instances For
The nondeterministic transition relation of the backward simulator.
Equations
- One or more equations did not get rendered due to their size.
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.init0 c = ∅
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.initSweep (some (Sum.inr (l, fst, ws))) = {(KurodaConstruction.KState.sim, some (Sum.inr (l, true, ws)), DLBA.Dir.stay)}
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.initSweep c = ∅
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.sim c = ∅
- KurodaConstruction.kTransition g₀ (KurodaConstruction.KState.applyRule r k) c = ∅
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.gotoLeft c = ∅
- KurodaConstruction.kTransition g₀ (KurodaConstruction.KState.check seen) (some (Sum.inr (l, r, some (symbol.terminal a)))) = ∅
- KurodaConstruction.kTransition g₀ (KurodaConstruction.KState.check seen) c = ∅
- KurodaConstruction.kTransition g₀ KurodaConstruction.KState.accept c = ∅
Instances For
The simulating LBA: backward-reduce the input to the start symbol.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Decoding the work track #
formOf reads the sentential form represented on the tape: the non-blank work symbols, in
cell order. The simulation invariant is phrased in terms of formOf.
The sentential form represented by a tape's work track: the non-blank work symbols, in cell order.
Equations
- KurodaConstruction.formOf g₀ c = List.filterMap (fun (γ : KurodaConstruction.KGamma g₀) => γ.2.2) (List.ofFn c)
Instances For
The sentential form represented by a work function W (the marked tape is mkCell ∘ W):
the non-blank work symbols, in order. This is what the simulation tracks: after init the tape is
always mkCell ∘ W, and applyRule updates W.
Equations
- KurodaConstruction.formW g₀ W = List.filterMap id (List.ofFn W)
Instances For
Reading the non-blank tail at a blank cell: the blank contributes nothing.
A backward rule-write output_string ↦ patList (in any context) is exactly one forward
grammar step … patList … → … output_string …. The soundness invariant prepends this step.
Step-level glue #
The only accepting state is accept.
Build one Step of kMachine from a transition membership.
Reaching an accept-state configuration witnesses acceptance.
An echo step that moves the head left by one, leaving the tape contents unchanged (the transition rewrites the current cell to its own value).
An echo step that moves the head right by one, leaving the tape contents unchanged.
An echo step that keeps the head in place, leaving the tape contents unchanged.
The gotoLeft sweep: from any head position, echo-move left to the marked left end (cell 0)
and enter the accept check.
Updating one cell of a canonical tape with mkCell i x corresponds to updating the work
function at i.
The accept-check sweep: if the work track spells exactly [S] (one cell j holds the start
symbol, all others blank), the check started at any cell i (with the seen flag tracking
whether j is behind i) reaches the accepting state.
If the work track spells exactly [S], the simulator accepts (from any head position):
roam to the left end and run the accept-check sweep.
The init conversion sweep #
The tape with cells < i converted, the rest still raw input some (Sum.inl _).
Equations
- KurodaConstruction.cAt g₀ input i k = if ↑k < i then KurodaConstruction.tmpCell g₀ input k else some (Sum.inl (input k))
Instances For
The transition-membership for converting an input cell i ≠ 0.
The conversion sweep: from cell i ≥ 1 (with cells < i converted), convert the rest of the
input left-to-right, ending (after the right-end clamp) at the fully-converted tape on cell n.
The init phase up to the right-end clamp: from the raw input tape (state init0, head 0),
reach the fully-converted (isRightEnd = false) tape at cell n.
The full init phase: from the raw input tape, reach the canonical marked work tape (state
sim), whose work track holds terminal (input k) at every cell (so formOf = input.map).