Documentation

Complexitylib.Models.TuringMachine.GuessStream

Guessing in designated states #

Complexitylib.Models.TuringMachine.GuessTape pairs NTM.ofGuess M with NTM.choiceTM, which forces M to consume a guess at every step. No machine assembled from Complexitylib.Models.TuringMachine.Combinators does that: the handoff step of TM.seqTM, and every step of a subroutine that has no interest in the guesses, leaves the tape's head where it is. This file drops that requirement.

A machine here nominates a set of advancing states. In an advancing state it consumes the cell under the guess head and moves that head on; in every other state it neither consults the guess tape nor moves its head. Between the two lies the whole deterministic subroutine library, usable unchanged.

The price is that the guess tape's head and the step counter part company: at step i the head sits at the cursor, the number of advancing steps so far. NTM.ofGuess M still consumes one choice per step, so the correspondence between a loaded tape and a choice sequence is no longer the identity — it is the cursor. NTM.exists_guessTape is what makes it work in the direction a soundness proof needs: every choice sequence is realized by some loaded tape, because the choices made at non-advancing steps are the ones the machine never looks at.

Main definitions #

Main results #

def Complexity.TM.traceD {n : } (M : TM n) :
Cfg n M.QCfg n M.Q

Run a deterministic machine for T steps, staying put once halted. The deterministic counterpart of NTM.trace.

Equations
Instances For
    @[simp]
    theorem Complexity.TM.traceD_zero {n : } (M : TM n) (c : Cfg n M.Q) :
    M.traceD 0 c = c
    theorem Complexity.TM.traceD_succ_of_not_halted {n : } (M : TM n) (T : ) {c : Cfg n M.Q} (h : c.state M.qhalt) :
    M.traceD (T + 1) c = M.traceD T (M.stepCfg c)
    theorem Complexity.TM.traceD_of_halted {n : } (M : TM n) (T : ) {c : Cfg n M.Q} (h : c.state = M.qhalt) :
    M.traceD T c = c
    theorem Complexity.TM.traceD_succ_back {n : } (M : TM n) (T : ) (c : Cfg n M.Q) :
    M.traceD (T + 1) c = if (M.traceD T c).state = M.qhalt then M.traceD T c else M.stepCfg (M.traceD T c)

    A run of T + 1 steps is a run of T steps followed by one more.

    theorem Complexity.TM.reachesIn_traceD {n : } (M : TM n) (T : ) (c : Cfg n M.Q) :
    tT, M.reachesIn t c (M.traceD T c) (t < TM.halted (M.traceD T c))

    A fixed-length run is a reachesIn run, stopped early exactly when the machine halts.

    def Complexity.TM.visible {k : } {Q : Type} (r : Q × (Fin (k + 1)Γw) × Γw × Dir3 × (Fin (k + 1)Dir3) × Dir3) :
    Q × (Fin kΓw) × Γw × Dir3 × (Fin kDir3) × Dir3

    The part of a transition that survives forgetting the guess tape.

    Equations
    Instances For
      structure Complexity.TM.GuessProtocol {k : } (M : TM (k + 1)) (Adv : M.QBool) :

      The guess protocol. In an advancing state the machine consumes the cell under the guess head and moves that head on; in every other state it holds the head still and nothing visible depends on what the cell holds. The guess tape's contents are never altered.

      Instances For
        theorem Complexity.TM.traceD_of_reachesIn {n : } (M : TM n) (t : ) {c c' : Cfg n M.Q} :
        M.reachesIn t c c'M.traceD t c = c'

        A run of a fixed length is the deterministic trace. A machine's step is a function, so the configuration reached in exactly t steps is TM.traceD t.

        theorem Complexity.TM.traceD_add {n : } (M : TM n) (a b : ) (c : Cfg n M.Q) :
        M.traceD (a + b) c = M.traceD b (M.traceD a c)

        Traces compose.

        theorem Complexity.TM.traceD_of_reachesIn_halted {n : } (M : TM n) {t T : } (hle : t T) {c c' : Cfg n M.Q} (h : M.reachesIn t c c') (hhalt : M.halted c') :
        M.traceD T c = c'

        Once halted, a longer trace stays put.

        theorem Complexity.NTM.ofGuess_δ {k : } (M : TM (k + 1)) (b : Bool) (q : M.Q) (iHead : Γ) (ww : Fin kΓ) (oHead : Γ) :
        (ofGuess M).δ b q iHead ww oHead = TM.visible (M.δ q iHead (Fin.snoc ww (Γ.ofBool b)) oHead)

        The transition of NTM.ofGuess M is the visible part of M's.

        theorem Complexity.NTM.dropChoice_stepCfg {k : } (M : TM (k + 1)) {c : Cfg (k + 1) M.Q} {b : Bool} (hread : (c.work (Fin.last k)).read = Γ.ofBool b) :

        One step of M is one step of NTM.ofGuess M along the bit under the guess head.

        def Complexity.NTM.nrunAt {k : } (N : NTM k) (choices : Bool) (c : Cfg k N.Q) :
        Cfg k N.Q

        Run a nondeterministic machine forward, taking the i-th choice at step i. Unlike NTM.trace, which consumes its choices from the front, this indexes them absolutely, which is what a statement about "the step at which a guess was consumed" needs.

        Equations
        Instances For
          @[simp]
          theorem Complexity.NTM.nrunAt_zero {k : } (N : NTM k) (choices : Bool) (c : Cfg k N.Q) :
          N.nrunAt choices c 0 = c
          theorem Complexity.NTM.nrunAt_succ {k : } (N : NTM k) (choices : Bool) (c : Cfg k N.Q) (i : ) :
          N.nrunAt choices c (i + 1) = if (N.nrunAt choices c i).state = N.qhalt then N.nrunAt choices c i else N.stepCfg (choices i) (N.nrunAt choices c i)
          theorem Complexity.NTM.nrunAt_of_halted {k : } (N : NTM k) (choices : Bool) {c : Cfg k N.Q} (h : c.state = N.qhalt) (i : ) :
          N.nrunAt choices c i = c
          theorem Complexity.NTM.nrunAt_succ_front {k : } (N : NTM k) (choices : Bool) {c : Cfg k N.Q} (h : c.state N.qhalt) (i : ) :
          N.nrunAt choices c (i + 1) = N.nrunAt (fun (j : ) => choices (j + 1)) (N.stepCfg (choices 0) c) i
          theorem Complexity.NTM.trace_eq_nrunAt {k : } (N : NTM k) (choices : Bool) (T : ) (c : Cfg k N.Q) :
          N.trace T (fun (i : Fin T) => choices i) c = N.nrunAt choices c T

          The absolutely-indexed run is NTM.trace.

          def Complexity.NTM.guessBit {k : } (M : TM (k + 1)) (c : Cfg (k + 1) M.Q) (i : ) :

          The bit the machine reads off its guess tape at step i.

          Equations
          Instances For
            theorem Complexity.NTM.boolFrom_stepCfg {k : } (M : TM (k + 1)) {Adv : M.QBool} (hP : M.GuessProtocol Adv) {T : } {c : Cfg (k + 1) M.Q} (hq : c.state M.qhalt) (h : (c.work (Fin.last k)).BoolFrom (T + 1)) :

            A step preserves the guess tape and moves its head at most one cell right, so a tape holding bits for T + 1 cells still holds them for T.

            theorem Complexity.NTM.dropChoice_traceD {k : } (M : TM (k + 1)) {Adv : M.QBool} (hP : M.GuessProtocol Adv) (T : ) (c : Cfg (k + 1) M.Q) :
            (c.work (Fin.last k)).BoolFrom TdropChoice (M.traceD T c) = (ofGuess M).trace T (fun (i : Fin T) => guessBit M c i) (dropChoice c)

            A run of M is a trace of NTM.ofGuess M along the bits it reads.

            Every choice sequence comes from a loaded tape #

            theorem Complexity.NTM.stepCfg_indep {k : } (M : TM (k + 1)) {Adv : M.QBool} (hP : M.GuessProtocol Adv) {c : Cfg k M.Q} (hq : c.state M.qhalt) (h : ¬Adv c.state = true) (b b' : Bool) :
            (ofGuess M).stepCfg b c = (ofGuess M).stepCfg b' c

            Outside the advancing states the choice bit does not matter.

            def Complexity.NTM.attach {k : } {Q : Type} (d : Cfg k Q) (τ : Tape) :
            Cfg (k + 1) Q

            Attach a guess tape to a configuration.

            Equations
            Instances For
              @[simp]
              theorem Complexity.NTM.attach_work_last {k : } {Q : Type} (d : Cfg k Q) (τ : Tape) :
              (attach d τ).work (Fin.last k) = τ
              @[simp]
              theorem Complexity.NTM.dropChoice_attach {k : } {Q : Type} (d : Cfg k Q) (τ : Tape) :
              @[simp]
              theorem Complexity.NTM.attach_state {k : } {Q : Type} (d : Cfg k Q) (τ : Tape) :
              (attach d τ).state = d.state
              theorem Complexity.NTM.loadCfg_eq_attach {k : } (M : TM (k + 1)) (x : List Bool) (g : Bool) :

              The largest index below T at which P holds, or 0 if there is none.

              Equations
              Instances For
                theorem Complexity.NTM.searchIdx_eq {P : Bool} {T i : } (hi : i < T) (hP : P i = true) (huniq : ∀ (j : ), P j = truej = i) :
                searchIdx P T = i
                def Complexity.NTM.consumes {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) (i : ) :

                Whether the nondeterministic run consumes a guess at step i.

                Equations
                Instances For
                  def Complexity.NTM.cursor {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) :

                  Where the guess head sits after i steps: one cell on for every guess consumed.

                  Equations
                  Instances For
                    theorem Complexity.NTM.one_le_cursor {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) (i : ) :
                    1 cursor M Adv choices d i
                    theorem Complexity.NTM.cursor_le_succ {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) (i : ) :
                    cursor M Adv choices d i cursor M Adv choices d (i + 1)
                    theorem Complexity.NTM.cursor_mono {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) {i j : } :
                    i jcursor M Adv choices d i cursor M Adv choices d j
                    theorem Complexity.NTM.cursor_lt_of_consumes {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) {i j : } (hij : i < j) (hi : consumes M Adv choices d i = true) :
                    cursor M Adv choices d i < cursor M Adv choices d j
                    theorem Complexity.NTM.cursor_inj_of_consumes {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) {i j : } (hi : consumes M Adv choices d i = true) (hj : consumes M Adv choices d j = true) (h : cursor M Adv choices d i = cursor M Adv choices d j) :
                    i = j
                    def Complexity.NTM.guessOf {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) (T p : ) :

                    The guess string that realizes a choice sequence. Cell p + 1 holds the choice made at the step whose cursor is p + 1; cells no advancing step ever reads hold whatever falls out.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      theorem Complexity.NTM.guessOf_eq {k : } (M : TM (k + 1)) (Adv : M.QBool) (choices : Bool) (d : Cfg k M.Q) {T i : } (hi : i < T) (hc : consumes M Adv choices d i = true) :
                      guessOf M Adv choices d T (cursor M Adv choices d i - 1) = choices i
                      theorem Complexity.NTM.work_last_stepCfg' {k : } (M : TM (k + 1)) {Adv' : M.QBool} (hP : M.GuessProtocol Adv') (c : Cfg (k + 1) M.Q) (hq : c.state M.qhalt) (hread : (c.work (Fin.last k)).read Γ.start) :

                      A step moves the guess head on exactly in the advancing states.

                      theorem Complexity.NTM.traceD_guessOf {k : } (M : TM (k + 1)) (choices : Bool) (d : Cfg k M.Q) {Adv : M.QBool} (hP : M.GuessProtocol Adv) (T i : ) :
                      i TdropChoice (M.traceD i (attach d (loadTape (guessOf M Adv choices d T)))) = (ofGuess M).nrunAt choices d i (M.traceD i (attach d (loadTape (guessOf M Adv choices d T)))).work (Fin.last k) = { head := cursor M Adv choices d i, cells := (loadTape (guessOf M Adv choices d T)).cells }

                      Every choice sequence is realized by a loaded guess tape. Running M on the tape NTM.guessOf builds reproduces, step for step, the path of NTM.ofGuess M along choices: the guesses land where the advancing steps read them, and the bits the machine never looks at are free.

                      theorem Complexity.NTM.exists_loadTape {k : } (M : TM (k + 1)) {Adv : M.QBool} (hP : M.GuessProtocol Adv) (x : List Bool) (T : ) (choices : Fin TBool) :
                      ∃ (g : Bool) (c' : Cfg (k + 1) M.Q), tT, M.reachesIn t (loadCfg M x g) c' (t < TM.halted c') dropChoice c' = (ofGuess M).trace T choices ((ofGuess M).initCfg x)

                      A path of NTM.ofGuess M is a run of M on a loaded guess tape. This is the transfer a nondeterministic construction is built on: design and verify M deterministically, with its guesses arriving on the last work tape, and read the result off here as a statement about the paths of NTM.ofGuess M. Unlike NTM.ofGuess_trace it asks nothing of M between guesses, so M may be assembled from the ordinary deterministic combinators.