Documentation

Complexitylib.Classes.Containments.Internal.SpaceIterate

Iterating a polynomial-time function in polynomial space #

⚠️ Unreviewed by Bolton

A language decided by iterating a polynomial-time function on a polynomially bounded state is in PSPACE, however many iterations it takes: the state is the only thing that has to be stored, and the iteration count lives in a binary counter of polynomially many bits. This is the machine-independent way into PSPACE, the counterpart of what Cobham's theorem does for P — and it is what Savitch's theorem needs, since Savitch's recursion is a stack machine whose step is polynomial-time and whose stack is polynomially bounded.

The machine reuses the iteration machinery of Complexitylib.Classes.P.Cobham.Internal.Iterate wholesale, on that file's own layout: Cobham.iterSetup puts pair [] x in place, Cobham.iterTail builds the entry shape, and Cobham.iterBody applies the function once and restores it. Only the loop driver changes. TM.forRegTM counts in unary, which cannot reach 2 ^ poly, so the loop here is TM.loopTM, as in PP ⊆ PSPACE and PH ⊆ PSPACE.

No tape is added #

Two of the layout's tapes are free for the loop's own use, so the machine needs no tapes beyond the ones Cobham.iterBody already has — and therefore no placement, and no parking of tapes a placement would freeze.

The machine never reads the counter: it is there so that TM.loopTM_hoareTime_indexed can read the iteration index off the tapes for its termination measure, which is why it may be binary and cost only polynomially many cells.

The loop's shape #

The programmed function signals completion by putting a 1 at the head of its state, and the loop's test is TM.writeOutputBitTM reading the state tape's first cell — so the loop runs until the computation says it is done, and the number of iterations never has to be represented. One more application after the loop puts the verdict at the head of the state, and a second TM.writeOutputBitTM publishes it.

Main definitions #

Main results #

The verdict cell #

The output tape holding s in its verdict cell.

Equations
Instances For

    The symbol at the head of a state #

    The symbol at the head of a state tape: the state's first bit, or blank.

    Equations
    Instances For

      Reading the iteration index off the tapes #

      TM.loopTM_hoareTime_indexed needs the iteration index as a function of the configuration, for its termination measure. The counter carries it; this is the ghost read, and nothing computes it.

      noncomputable def Complexity.SpaceIter.ctrValue (t : Tape) :

      The value a canonical binary register holds.

      Equations
      Instances For
        noncomputable def Complexity.SpaceIter.loopIdx (k start : ) :
        Tape(Fin (3 + (k + 2) + 0)Tape)Tape

        The loop's index function: how far the counter has advanced past start. The input and output tapes are ignored, but TM.loopTM_hoareTime_indexed takes the index as a function of the whole configuration, so they have to be there.

        Equations
        Instances For

          The tapes of an iteration #

          noncomputable def Complexity.SpaceIter.iterBank {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
          Fin (3 + (k + 2) + 0)Tape

          The tape family at an iteration: the entry shape for y on the application block, the counter on the fuel register, and the two fixed tapes.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            @[simp]
            theorem Complexity.SpaceIter.iterBank_app {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) (j : Fin (k + 2)) :
            iterBank M y inp₀ junkT H c (appIdx j) = M.applyPre y inp₀ j
            theorem Complexity.SpaceIter.iterBank_book {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) (i : Fin (3 + (k + 2) + 0)) (hi : ¬TM.placeWorkInMiddle 3 (k + 2) i) :
            iterBank M y inp₀ junkT H c i = bookTapes (natTape c) junkT H i
            @[simp]
            theorem Complexity.SpaceIter.iterBank_rf {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
            iterBank M y inp₀ junkT H c rfIdx = natTape c
            @[simp]
            theorem Complexity.SpaceIter.iterBank_wf {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
            iterBank M y inp₀ junkT H c wfIdx = TM.regTape H
            @[simp]
            theorem Complexity.SpaceIter.iterBank_junk {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
            iterBank M y inp₀ junkT H c junkIdx = junkT
            @[simp]
            theorem Complexity.SpaceIter.iterBank_res {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
            iterBank M y inp₀ junkT H c resIdx = TM.parkedBlank
            theorem Complexity.SpaceIter.iterBank_parked {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hjunkP : TM.Parked junkT) (H c : ) (i : Fin (3 + (k + 2) + 0)) :
            TM.Parked (iterBank M y inp₀ junkT H c i)
            theorem Complexity.SpaceIter.iterBank_head {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hjunkh : junkT.head 1) (H c : ) (i : Fin (3 + (k + 2) + 0)) :
            (iterBank M y inp₀ junkT H c i).head 1

            Every tape of the bank is parked at cell one.

            theorem Complexity.SpaceIter.iterBank_eq {k : } (M : TM k) (z : List Bool) (inp₀ junkT : Tape) (H c : ) (W : Fin (3 + (k + 2) + 0)Tape) (happ : ∀ (j : Fin (k + 2)), W (appIdx j) = M.applyPre z inp₀ j) (hrf : W rfIdx = natTape c) (hwf : W wfIdx = TM.regTape H) (hjunk : W junkIdx = junkT) :
            W = iterBank M z inp₀ junkT H c

            A block family is the iteration bank as soon as it has the right tapes.

            theorem Complexity.SpaceIter.iterBank_trans {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hjunkP : TM.Parked junkT) (H c : ) :
            (fun (i : Fin (3 + (k + 2) + 0)) => TM.transitionTape (iterBank M y inp₀ junkT H c i)) = iterBank M y inp₀ junkT H c

            A parked bank survives a phase boundary.

            theorem Complexity.SpaceIter.iterBank_succ {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
            iterBank M y inp₀ junkT H (c + 1) = Function.update (iterBank M y inp₀ junkT H c) rfIdx (natTape (c + 1))

            The counter is the only tape that changes when the count does.

            The machine #

            def Complexity.SpaceIter.bodyTM {k : } (M : TM k) :
            TM (3 + (k + 2) + 0)

            The loop body: clear the verdict cell, apply the function once, bump the counter.

            Equations
            Instances For
              def Complexity.SpaceIter.testTM (k : ) :
              TM (3 + (k + 2) + 0)

              The loop test: publish the head symbol of the state.

              Equations
              Instances For

                The body's contract #

                theorem Complexity.SpaceIter.clear_hoareTime {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H c : ) (s : Γ) (hs : s Γ.start) :
                (TM.writeOutputBitTM resIdx).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = slotOf s) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = TM.parkedBlank) 1

                Clearing the verdict cell, from the blank result tape.

                theorem Complexity.SpaceIter.apply_hoareTime {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H c : ) (hHy : y.length H) (hHT : 1 + T y.length H) (hGy : (G y).length + 1 H) :
                (iterBody M).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = TM.parkedBlank) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M (G y) inp₀ junkT H c out = TM.parkedBlank) (T y.length + 1 + tailBound k H (G y).length)

                Applying the function once.

                theorem Complexity.SpaceIter.bump_hoareTime {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H c : ) :
                (TM.binarySuccTM rfIdx).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = TM.parkedBlank) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H (c + 1) out = TM.parkedBlank) (TM.binarySuccTime c)

                Bumping the counter.

                theorem Complexity.SpaceIter.bodyTM_hoareTime {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H c : ) (hHy : y.length H) (hHT : 1 + T y.length H) (hGy : (G y).length + 1 H) (s : Γ) (hs : s Γ.start) :
                (bodyTM M).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = slotOf s) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M (G y) inp₀ junkT H (c + 1) out = TM.parkedBlank) (1 + 1 + (T y.length + 1 + tailBound k H (G y).length) + 1 + TM.binarySuccTime c)

                The loop body's contract.

                The test's contract #

                theorem Complexity.SpaceIter.iterBank_vin_read {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (H c : ) :
                (iterBank M y inp₀ junkT H c vinIdx).read = headSym y

                The state tape of a bank reads the state's first symbol.

                theorem Complexity.SpaceIter.testTM_hoareTime {k : } (M : TM k) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H c : ) :
                (testTM k).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = TM.parkedBlank) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = slotOf (TM.readBackWrite (headSym y)).toΓ) 1

                The loop's test. It publishes the state's first symbol; the programmed function signals completion by putting a 1 there.

                The loop #

                The verdict cell at the start of a pass: blank before the first test, the previous test's verdict afterwards.

                Equations
                Instances For
                  noncomputable def Complexity.SpaceIter.loopState {k : } (M : TM k) (Y : List Bool) (inp₀ junkT : Tape) (H start j : ) :
                  TapePred (3 + (k + 2) + 0)

                  The loop's state after j passes, with the counter offset by its starting value.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    theorem Complexity.SpaceIter.loopState_parked {k : } (M : TM k) (Y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H start j : ) (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) :
                    loopState M Y inp₀ junkT H start j inp work outTM.LoopParked inp work out
                    noncomputable def Complexity.SpaceIter.midState {k : } (M : TM k) (Y : List Bool) (inp₀ junkT : Tape) (H start j : ) :
                    TapePred (3 + (k + 2) + 0)

                    The tapes between the body and the test of a pass: the entry shape for the next state, with the verdict cell cleared.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For
                      theorem Complexity.SpaceIter.body_pass {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (Y : List Bool) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H start N : ) (hHy : iN, (Y i).length + 1 H) (hHT : i < N, 1 + T (Y i).length H) (j : ) (hj : j < N) :
                      (bodyTM M).HoareTime (loopState M Y inp₀ junkT H start j) (midState M Y inp₀ junkT H start j) (1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (start + j))

                      The body of a pass applies the function once and bumps the counter.

                      theorem Complexity.SpaceIter.midState_parked {k : } (M : TM k) (Y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H start j : ) (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) :
                      midState M Y inp₀ junkT H start j inp work outTM.LoopParked inp work out

                      The tapes between the body and the test are parked.

                      theorem Complexity.SpaceIter.test_pass {k : } (M : TM k) (Y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hjunkP : TM.Parked junkT) (H start j : ) :
                      (testTM k).HoareTime (midState M Y inp₀ junkT H start j) (loopState M Y inp₀ junkT H start (j + 1)) 1

                      The test of a pass publishes the next state's head symbol.

                      theorem Complexity.SpaceIter.loop_pass {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (Y : List Bool) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H start N : ) (hHy : iN, (Y i).length + 1 H) (hHT : i < N, 1 + T (Y i).length H) (hcont : ∀ (i : ), 0 < ii < N(Y i).headD false = false) (b : ) (hb : j < N, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (start + j) + 1 + 5 b) (j : ) :
                      j < N - 1∀ (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape), loopState M Y inp₀ junkT H start j inp work out∃ (inp' : Tape) (work' : Fin (3 + (k + 2) + 0)Tape) (out' : Tape) (t : ), 1 t t b ((bodyTM M).loopTM (testTM k)).reachesIn t { state := ((bodyTM M).loopTM (testTM k)).qstart, input := inp, work := work, output := out } { state := ((bodyTM M).loopTM (testTM k)).qstart, input := inp', work := work', output := out' } loopState M Y inp₀ junkT H start (j + 1) inp' work' out'

                      One pass of the loop. The body applies the function once, and the test finds the state not yet done, so the loop comes back to its start state one iteration on.

                      theorem Complexity.SpaceIter.loop_final {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (Y : List Bool) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H start N : ) (hN : 1 N) (hHy : iN, (Y i).length + 1 H) (hHT : i < N, 1 + T (Y i).length H) (hdone : (Y N).headD false = true) (b : ) (hb : j < N, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (start + j) + 1 + 5 b) (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) :
                      loopState M Y inp₀ junkT H start (N - 1) inp work out∃ (c' : Cfg (3 + (k + 2) + 0) ((bodyTM M).loopTM (testTM k)).Q), tb, ((bodyTM M).loopTM (testTM k)).reachesIn t { state := ((bodyTM M).loopTM (testTM k)).qstart, input := inp, work := work, output := out } c' ((bodyTM M).loopTM (testTM k)).halted c' loopState M Y inp₀ junkT H start N c'.input c'.work c'.output

                      The last pass of the loop. The body applies the function one final time, and the test finds the state done, so the loop halts.

                      theorem Complexity.SpaceIter.loop_hoareTime {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (Y : List Bool) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H start N : ) (hN : 1 N) (hHy : iN, (Y i).length + 1 H) (hHT : i < N, 1 + T (Y i).length H) (hcont : ∀ (i : ), 0 < ii < N(Y i).headD false = false) (hdone : (Y N).headD false = true) (b : ) (hb : j < N, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (start + j) + 1 + 5 b) :
                      ((bodyTM M).loopTM (testTM k)).HoareTime (loopState M Y inp₀ junkT H start 0) (loopState M Y inp₀ junkT H start N) ((N - 1 + 1) * b)

                      The loop's contract. The loop runs until the state says it is done: N passes, each applying the function once.

                      theorem Complexity.SpaceIter.loop_keepsWindowOn {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (Y : List Bool) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H start N : ) (hN : 1 N) (hHy : iN, (Y i).length + 1 H) (hHT : i < N, 1 + T (Y i).length H) (hcont : ∀ (i : ), 0 < ii < N(Y i).headD false = false) (hdone : (Y N).headD false = true) (b : ) (hb : j < N, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (start + j) + 1 + 5 b) (lx h₀ : ) (hh₀ : 1 h₀) (hinph : inp₀.head lx + h₀ + 1) (hjunkh : junkT.head 1) :
                      ((bodyTM M).loopTM (testTM k)).KeepsWindowOn (fun (c : Cfg (3 + (k + 2) + 0) ((bodyTM M).loopTM (testTM k)).Q) => c.state = ((bodyTM M).loopTM (testTM k)).qstart loopState M Y inp₀ junkT H start 0 c.input c.work c.output) lx (h₀ + b)

                      The loop's window. Every configuration the loop passes through lies within one pass of an indexed state, and each indexed state has every head parked at cell one, so a window one pass wide holds for the whole run — however many passes it takes.

                      The prologue #

                      Cobham.iterSetup puts pair [] x on the result tape with the bookkeeping registers loaded, and Cobham.iterTail turns that into the entry shape the loop starts from — exactly the two phases Cobham.iterTM opens with.

                      def Complexity.SpaceIter.prologueTM (k : ) (p : Polynomial ) :
                      TM (3 + (k + 2) + 0)

                      The prologue: the setup, then the tail that builds the entry shape.

                      Equations
                      Instances For

                        The prologue's running time, which is also the width its window needs.

                        Equations
                        Instances For

                          The counter's starting value. Cobham.iterSetup leaves |x| in unary on the fuel register, and a unary register of n ones read as a binary numeral is 2 ^ n - 1.

                          Equations
                          Instances For
                            theorem Complexity.SpaceIter.prologueTM_hoareTime {k : } (M : TM k) (p : Polynomial ) (x : List Bool) (H : ) (hH : H = Polynomial.eval x.length p) (hHx : x.length + 4 H) :
                            (prologueTM k p).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = Tape.init (List.map Γ.ofBool x) (work = fun (x : Fin (3 + (k + 2) + 0)) => Tape.init []) out = Tape.init []) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => TM.Parked inp inp.StartInvariant work = iterBank M (pair [] x) inp (TM.regTape H) H (startCount x.length) out = TM.parkedBlank) (proBound k p H x.length)

                            The prologue's contract. From the initial configuration's tapes it reaches the loop's entry state for pair [] x, with the counter at startCount |x|.

                            The epilogue #

                            The loop leaves the state saying it is done; one more application turns that state into the one whose head is the answer, and one more publication puts it in the verdict cell.

                            def Complexity.SpaceIter.epilogueTM {k : } (M : TM k) :
                            TM (3 + (k + 2) + 0)

                            The epilogue: one more application, then publish the state's head.

                            Equations
                            Instances For
                              theorem Complexity.SpaceIter.epilogueTM_hoareTime {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (y : List Bool) (inp₀ junkT : Tape) (hinpP : TM.Parked inp₀) (hinpSI : inp₀.StartInvariant) (hjunkP : TM.Parked junkT) (hjunkSI : junkT.StartInvariant) (H c : ) (hHy : y.length H) (hHT : 1 + T y.length H) (hGy : (G y).length + 1 H) (s : Γ) (hs : s Γ.start) :
                              (epilogueTM M).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M y inp₀ junkT H c out = slotOf s) (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = inp₀ work = iterBank M (G y) inp₀ junkT H (c + 1) out = slotOf (TM.readBackWrite (headSym (G y))).toΓ) (1 + 1 + (T y.length + 1 + tailBound k H (G y).length) + 1 + TM.binarySuccTime c + 1 + 1)

                              The epilogue's contract.

                              The whole machine #

                              def Complexity.SpaceIter.spaceIterTM {k : } (M : TM k) (p : Polynomial ) :
                              TM (3 + (k + 2) + 0)

                              The iteration machine: prologue, loop, epilogue.

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                theorem Complexity.SpaceIter.spaceIterTM_hoareTime {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (p : Polynomial ) (x : List Bool) (H : ) (hH : H = Polynomial.eval x.length p) (hHx : x.length + 4 H) (Y : List Bool) (hY0 : Y 0 = pair [] x) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (N : ) (hN : 1 N) (hHy : iN + 1, (Y i).length + 1 H) (hHT : iN, 1 + T (Y i).length H) (hcont : ∀ (i : ), 0 < ii < N(Y i).headD false = false) (hdone : (Y N).headD false = true) (b : ) (hb : jN, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (startCount x.length + j) + 1 + 5 b) :
                                (spaceIterTM M p).HoareTime (fun (inp : Tape) (work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => inp = Tape.init (List.map Γ.ofBool x) (work = fun (x : Fin (3 + (k + 2) + 0)) => Tape.init []) out = Tape.init []) (fun (_inp : Tape) (_work : Fin (3 + (k + 2) + 0)Tape) (out : Tape) => out = slotOf (TM.readBackWrite (headSym (Y (N + 1)))).toΓ) (proBound k p H x.length + 1 + (N - 1 + 1) * b + 1 + b)

                                The whole machine's contract. From the initial tapes on x it halts with the head symbol of Y (N + 1) in the verdict cell, where Y is the orbit of the programmed function through pair [] x and N is the first positive index at which the state says it is done.

                                The machine's window #

                                The prologue and the epilogue are short, so their windows come from their running times. The loop's does not — it runs for as long as the programmed computation does — but every configuration it passes through is within one pass of an indexed state whose heads are all parked, so one pass' width is enough.

                                theorem Complexity.SpaceIter.hoarePostOf {m : } {tm : TM m} {pre post : TapePred m} {bnd : } (h : tm.HoareTime pre post bnd) (c : Cfg m tm.Q) (hst : c.state = tm.qstart) (hpre : pre c.input c.work c.output) :
                                ∃ (e : Cfg m tm.Q), tm.reaches c e tm.halted e post e.input e.work e.output

                                A halting contract, read as a reachability fact about a configuration already in the machine's start state.

                                theorem Complexity.SpaceIter.spaceIterTM_keepsWindow {k : } (M : TM k) {G : List BoolList Bool} {T : } (hcomp : M.ComputesInTime G T) (p : Polynomial ) (x : List Bool) (H : ) (hH : H = Polynomial.eval x.length p) (hHx : x.length + 4 H) (Y : List Bool) (hY0 : Y 0 = pair [] x) (hY : ∀ (i : ), Y (i + 1) = G (Y i)) (N : ) (hN : 1 N) (hHy : iN + 1, (Y i).length + 1 H) (hHT : iN, 1 + T (Y i).length H) (hcont : ∀ (i : ), 0 < ii < N(Y i).headD false = false) (hdone : (Y N).headD false = true) (b : ) (hb : jN, 1 + 1 + (T (Y j).length + 1 + tailBound k H (Y (j + 1)).length) + 1 + TM.binarySuccTime (startCount x.length + j) + 1 + 5 b) (W : ) (hW : proBound k p H x.length + 1 + b W) (c : Cfg (3 + (k + 2) + 0) (spaceIterTM M p).Q) :

                                The whole machine's window.

                                Iterating a polynomial-time function in polynomial space #

                                Everything above is stated for an explicit H, N and per-pass bound b. Here they are supplied: H is the padding polynomial of Cobham.iterTM, b is one pass' running time, and the window is their sum — a polynomial, because the only unbounded quantity, the iteration count, enters only through the number of bits of the counter.

                                def Complexity.SpaceIter.passBound (k : ) (tp p r w : Polynomial ) (n : ) :

                                One pass' running time, as a function of the input length: an application of the programmed function, the tail that restores the entry shape, and an increment of a counter of n + w(n) + 1 bits.

                                Equations
                                • One or more equations did not get rendered due to their size.
                                Instances For

                                  The machine's window: the prologue, and one pass.

                                  Equations
                                  Instances For
                                    theorem Complexity.SpaceIter.startCount_add_size_le (n j W : ) (hj : j 2 ^ W) :
                                    (startCount n + j).size n + W + 1

                                    The counter never exceeds 2 ^ (n + w n + 1), so it takes n + w n + 1 bits.

                                    theorem Complexity.SpaceIter.mem_PSPACE_of_iterate {L : Language} {G : List BoolList Bool} (hG : G FP) (r w : Polynomial ) (Nof : List Bool) (hlen : ∀ (x : List Bool), iNof x + 1, (G^[i] (pair [] x)).length Polynomial.eval x.length r) (hN1 : ∀ (x : List Bool), 1 Nof x) (hNw : ∀ (x : List Bool), Nof x 2 ^ Polynomial.eval x.length w) (hcont : ∀ (x : List Bool) (i : ), 0 < ii < Nof x(G^[i] (pair [] x)).headD false = false) (hdone : ∀ (x : List Bool), (G^[Nof x] (pair [] x)).headD false = true) (hne : ∀ (x : List Bool), G^[Nof x + 1] (pair [] x) []) (hans : ∀ (x : List Bool), x L (G^[Nof x + 1] (pair [] x)).headD false = true) :

                                    Iterating a polynomial-time function on a polynomially bounded state is in PSPACE, however many iterations it takes. The function is applied to pair [] x over and over; it signals completion by putting a 1 at the head of its state, and the head of the state one application later is the answer.