Documentation

Cslib.Computability.Machines.Turing.MultiTape.ConfigBound

Bounds on the number of reachable configurations in bounded space #

A multi-tape Turing machine that uses at most s cells of work-tape space can only reach a number of configurations that differ in their storage content (state and work tapes) that is bounded exponentially in s. Together with the n + 2 possible positions of the input head this bounds the number of configurations the machine can be in, disregarding the write-only output tape.

Important Definitions #

The results are layered, from the purely combinatorial to the machine-specific:

Design #

The write-only output tape is never read by step, so it can be dropped: what a machine can still react to is its Cfg.core, the pair of the input head position and the Storage. The input head position, in contrast, is read, so it cannot be dropped and has to be counted, which is where the factor n + 2 comes from (the input head may move one step off the input in either direction).

Starting from the all-blank tapes with every head at 0 and moving by at most one cell per step, a computation in which tape i has visited at most sᵢ cells keeps that tape's head position and every non-blank cell within the per-tape window [-sᵢ, sᵢ].

Hence a storage is determined by finite data over these windows, and counting it gives the per-tape product ∏ᵢ (2 sᵢ + 1) · (|Symbol| + 1)^(2 sᵢ + 1). Since the tapes share the total space budget (∑ᵢ sᵢ ≤ s), this collapses to an expression with the total space (2s + k) as the alphabet exponent.

We lose a factor of 2 * k by simplifying the windows to [-sᵢ, sᵢ] instead of the actually used area, but this is absorbed by the O(s) exponent in the final bound.

The windows for a whole run are available because a machine that is space-bounded at every point in time attains its per-tape space usage at a single step (MultiTapeTM.exists_spaceUsedByTape_max).

Storage #

Defines the core data structure for this file, Storage, which contains the state and the work tapes of a multi-tape Turing machine, with the work tape cells indexed over all of . It is thus equivalent to a projection of Cfg.

Then BoundedStorage is introduced, which restricts the cells and the head position of each tape to a window [-s, s] (with a different s for each tape) and is therefore a finite type. It is proven that the restriction map is injective on those Storages whose non-blank cells and head positions all lie inside the [-s, s] windows, so that counting BoundedStorage bounds the number of such Storages.

structure Turing.Storage (Symbol : Type u_3) (State : Type u_4) (k : ) :
Type (max u_3 u_4)

The state and work-tape data of a machine.

Instances For
    theorem Turing.Storage.ext_iff {Symbol : Type u_3} {State : Type u_4} {k : } {x y : Storage Symbol State k} :
    theorem Turing.Storage.ext {Symbol : Type u_3} {State : Type u_4} {k : } {x y : Storage Symbol State k} (state : x.state = y.state) (workTapes : x.workTapes = y.workTapes) (workTapePos : x.workTapePos = y.workTapePos) :
    x = y

    The window [-s, s] of tape positions allotted to a tape that uses s cells.

    Equations
    Instances For
      theorem Turing.mem_window {s : } {z : } :
      @[simp]
      theorem Turing.card_window (s : ) :
      (window s).card = 2 * s + 1
      @[reducible, inline]
      abbrev Turing.BoundedStorage (Symbol : Type u_3) (State : Type u_4) {k : } (w : Fin k) :
      Type (max u_4 u_3)

      A bounded storage: the state and work-tape data of a machine, but with the cells and the head position of tape i restricted to the finite window [-(w i), w i].

      Equations
      Instances For
        structure Turing.Storage.FitsIn {k : } {State : Type u_1} {Symbol : Type u_2} (x : Storage Symbol State k) (w : Fin k) :

        A storage fits in the per-tape windows w: on each tape j, the head position and every non-blank cell have absolute value ≤ w j.

        Instances For
          theorem Turing.Storage.FitsIn_mono {k : } {State : Type u_1} {Symbol : Type u_2} {x : Storage Symbol State k} :

          If a Storage fits in a smaller window, it also fits in the larger window.

          def Turing.Storage.toBounded {k : } {State : Type u_1} {Symbol : Type u_2} (x : Storage Symbol State k) (w : Fin k) :
          BoundedStorage Symbol State w

          Restriction of a storage to the finite windows w (with heads outside their window clamped to 0).

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            theorem Turing.Storage.toBounded_injOn {k : } {State : Type u_1} {Symbol : Type u_2} (w : Fin k) :
            Set.InjOn (fun (x : Storage Symbol State k) => x.toBounded w) {x : Storage Symbol State k | x.FitsIn w}

            The restriction is injective on storages that fit in the windows.

            Counting storages #

            This section is purely combinatorial: it counts how many values a Storage restricted to given windows can take, without reference to a machine or a run.

            def Turing.storageBound (Symbol : Type u_3) (State : Type u_4) [Fintype Symbol] [Fintype State] (k s : ) :

            An upper bound on the number of storages a k-tape machine can be in while using at most s cells of total work-tape space, over the given alphabet and state set. The (2s + 1)^k factor counts the possible head positions; the dominant factor (|Symbol| + 1)^(2s + k) uses the total space s in the exponent (the k tapes share the space budget).

            Equations
            Instances For
              theorem Turing.card_boundedStorage_le {k : } {State : Type u_1} {Symbol : Type u_2} [Fintype Symbol] [Fintype State] {w : Fin k} {s : } (hsum : i : Fin k, w i s) :
              Fintype.card (BoundedStorage Symbol State w) storageBound Symbol State k s

              The number of bounded storages is at most storageBound. Counting the tapes separately gives the per-tape product ∏ᵢ (2 wᵢ + 1) · (|Symbol| + 1) ^ (2 wᵢ + 1); each tape uses at most the total space s, and the tapes together use at most s, which collapses the alphabet exponent to 2s + k.

              theorem Turing.encard_fitsIn_le {k : } {State : Type u_1} {Symbol : Type u_2} [Fintype Symbol] [Fintype State] {w : Fin k} {s : } (hsum : i : Fin k, w i s) :
              {x : Storage Symbol State k | x.FitsIn w}.encard (storageBound Symbol State k s)

              The counting result at the heart of this file: a Storage whose non-blank cells and head positions stay within per-tape windows of total size at most s can take at most storageBound Symbol State k s different values.

              The exponential form of storageBound #

              This proves that storageBound is exponential in the space s.

              def Turing.storageBoundBase (Symbol : Type u_3) (State : Type u_4) [Fintype Symbol] [Fintype State] (k : ) :

              The base factor in the resulting exponential form of storageBound.

              Equations
              Instances For
                def Turing.storageBoundExp (Symbol : Type u_3) [Fintype Symbol] (k : ) :

                The factor in the exponent of the exponential form of storageBound.

                Equations
                Instances For
                  theorem Turing.storageBound_le_base_mul_pow {k : } {State : Type u_1} {Symbol : Type u_2} [Fintype Symbol] [Fintype State] (s : ) :
                  storageBound Symbol State k s storageBoundBase Symbol State k * 2 ^ (storageBoundExp Symbol k * s)

                  storageBound grows at most exponentially in the space s, with a constant factor and a factor in the exponent that only depend on the machine's alphabet, state set and tape count.

                  theorem Turing.storageBound_le_pow {k : } {State : Type u_1} {Symbol : Type u_2} [Fintype Symbol] [Fintype State] :
                  ∃ (a : ) (c : ), ∀ (s : ), storageBound Symbol State k s a * 2 ^ (c * s)

                  storageBound grows at most exponentially in the space s: there exist constants a and c (depending on the machine's alphabet, state set and tape count) with storageBound Symbol State k s ≤ a * 2 ^ (c * s) for all s.

                  The storage and the core of a configuration #

                  Now we relate Cfg and Storage by giving the projection.

                  def Turing.Cfg.storage {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} (c : Cfg k Symbol State input) :
                  Storage Symbol State k

                  This function maps a Cfg to Storage, forgetting the input head position and the write-only output tape.

                  Equations
                  Instances For
                    def Turing.Cfg.core {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} (c : Cfg k Symbol State input) :
                    Fin (input.length + 2) × Storage Symbol State k

                    The part of a configuration that the machine can still read: the input head position together with the Storage, i.e. the configuration without the write-only output tape.

                    Equations
                    Instances For
                      theorem Turing.core_step_eq_of_core_eq {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} {tm : MultiTapeTM k Symbol State} {c₁ c₂ : Cfg k Symbol State input} (h : c₁.core = c₂.core) :

                      step never reads the output tape, so the core of the next configuration is determined by the core of the current one.

                      The storages and cores of a space-bounded run #

                      These are the main results giving upper bounds on the number of storages and configuration cores reachable in bounded space.

                      theorem Turing.MultiTapeTM.storage_fitsIn {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} {tm : MultiTapeTM k Symbol State} (t : ) :

                      The storage reached after t steps fits in the windows given by the per-tape space usage up to step t.

                      theorem Turing.MultiTapeTM.encard_storages_le {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} {tm : MultiTapeTM k Symbol State} [Fintype Symbol] [Fintype State] {s : } (hs : ∀ (t : ), spaceUsed (initCfg input) t s) :
                      (Set.range fun (t : ) => (runFrom (initCfg input) t).storage).encard (storageBound Symbol State k s)

                      A machine that uses at most s cells of work-tape space at every point in time passes through at most storageBound Symbol State k s different storages during its whole run — independently of the length of the input and of how long it runs.

                      theorem Turing.MultiTapeTM.encard_cores_le {k : } {State : Type u_1} {Symbol : Type u_2} {input : List Symbol} {tm : MultiTapeTM k Symbol State} [Fintype Symbol] [Fintype State] {s : } (hs : ∀ (t : ), spaceUsed (initCfg input) t s) :
                      (Set.range fun (t : ) => (runFrom (initCfg input) t).core).encard (input.length + 2) * (storageBound Symbol State k s)

                      The number of configuration cores that a machine bounded by space s can reach is at most (n + 2) * storageBound Symbol State k s, where n is the length of the input.

                      theorem Turing.MultiTapeTM.encard_storages_le_pow {k : } {State : Type u_1} {Symbol : Type u_2} {tm : MultiTapeTM k Symbol State} [Finite Symbol] [Finite State] :
                      ∃ (a : ) (c : ), ∀ (input : List Symbol) (s : ), (∀ (t : ), spaceUsed (initCfg input) t s)(Set.range fun (t : ) => (runFrom (initCfg input) t).storage).encard a * 2 ^ (c * s)

                      The storage bound in exponential form: the number of storages a space-s-bounded machine passes through is at most 2 ^ (O(s)), with constants depending only on the machine.

                      theorem Turing.MultiTapeTM.encard_cores_le_pow {k : } {State : Type u_1} {Symbol : Type u_2} {tm : MultiTapeTM k Symbol State} [Finite Symbol] [Finite State] :
                      ∃ (a : ) (c : ), ∀ (input : List Symbol) (s : ), (∀ (t : ), spaceUsed (initCfg input) t s)(Set.range fun (t : ) => (runFrom (initCfg input) t).core).encard (input.length + 2) * a * 2 ^ (c * s)

                      The core bound in exponential form: the number of cores a space-s-bounded machine can reach is at most (n + 2) * 2 ^ (O(s)), with constants depending only on the machine and not on the input.