Documentation

Complexitylib.Models.RandomAccessMachine.Defs

Random access machines: model and cost measures #

This file defines a Random Access Machine (RAM) — a register machine with indirect addressing — together with logarithmic-cost time and space measures. The design follows the standard successor/register RAM of Cook–Reckhow, Time bounded random access machines (JCSS 7 (1973), 354–375) and the textbook presentations of Papadimitriou (Computational Complexity, §2.6) and van Emde Boas (Machine models and simulations, Handbook of Theoretical Computer Science A, 1990). Conventions are adapted for a clean formalization where a text is silent or divergent, but the cost measure is kept faithful to the literature, because it is exactly the cost measure that determines whether the model is a sound stand-in for a Turing machine.

Why logarithmic cost (the soundness point) #

A RAM stores natural numbers of unbounded magnitude in each register. Under the naive unit-cost measure — one time unit per instruction regardless of operand size — a RAM can square a register repeatedly to build the number 2 ^ (2 ^ k) in O(k) steps. That number needs 2 ^ k bits to write down, so no Turing machine can even emit it in fewer than 2 ^ k steps: unit-cost RAM time is super-polynomially stronger than Turing time, and the two models are not polynomially equivalent. Adopting unit cost and then comparing to Turing machines would be a category error — the exact "reward hacking" this model is designed to avoid. RAM.logGap_squaring in the surface file turns this into a theorem about this very model.

The logarithmic-cost measure charges each instruction the total bit-length of the numbers it manipulates (operand contents and, for indirect operands, the runtime addresses), plus a base cost of 1 so every step costs at least one time unit. Under this measure the RAM is polynomially equivalent to the multi-tape Turing machine of Complexitylib.Models.TuringMachine; the precise two-way simulation bounds are recorded in the surface module Complexitylib.Models.RandomAccessMachine.

Main definitions #

Design notes #

The RAM instruction set. Register indices and jump targets are natural numbers. add/sub/mul are three-address; sub is truncated subtraction (Nat monus). load/store use indirect addressing — the accessed register index is itself the content of a register — which is what makes the machine "random access".

  • imm (d v : ) : Instr

    imm d v: set R d := v (load an immediate constant).

  • add (d s t : ) : Instr

    add d s t: set R d := R s + R t.

  • sub (d s t : ) : Instr

    sub d s t: set R d := R s ∸ R t (truncated subtraction).

  • mul (d s t : ) : Instr

    mul d s t: set R d := R s * R t.

  • load (d a : ) : Instr

    load d a: indirect load R d := R (R a).

  • store (a s : ) : Instr

    store a s: indirect store R (R a) := R s.

  • jz (s tgt : ) : Instr

    jz s tgt: if R s = 0 jump to tgt, else fall through.

  • jmp (tgt : ) : Instr

    jmp tgt: unconditional jump to tgt.

  • halt : Instr

    halt: stop the machine.

Instances For
    Equations
    Instances For
      def Complexity.RAM.instDecidableEqInstr.decEq (x✝ x✝¹ : Instr) :
      Decidable (x✝ = x✝¹)
      Equations
      Instances For
        @[reducible, inline]

        A RAM program is a finite list of instructions, indexed by the program counter.

        Equations
        Instances For

          A RAM configuration: the program counter and the register file. Register i currently holds regs i.

          • pc :

            The program counter (index of the next instruction).

          • regs :

            The register file: regs i is the content of register i.

          Instances For
            theorem Complexity.RAM.Cfg.ext {x y : Cfg} (pc : x.pc = y.pc) (regs : x.regs = y.regs) :
            x = y
            theorem Complexity.RAM.Cfg.ext_iff {x y : Cfg} :
            x = y x.pc = y.pc x.regs = y.regs

            The length function l(v): the number of binary digits of v. bitlen 0 = 0, bitlen 1 = 1, bitlen (2 ^ k) = k + 1. This is the quantity charged (per operand) by the logarithmic cost measure.

            Equations
            Instances For

              The instruction the machine is about to execute. A program counter past the end of the program reads as halt, so programs need not end in halt.

              Equations
              Instances For

                A configuration is halted (for a given program) when the current instruction is halt — including the case of a program counter past the program end.

                Equations
                Instances For

                  Execute one instruction, producing the successor configuration. halt is a no-op here; step only applies this to a non-halted configuration.

                  Equations
                  Instances For

                    Step a RAM by one instruction (a no-op on a halted configuration).

                    Equations
                    Instances For

                      The logarithmic cost of executing instruction i in configuration c: the base cost 1 plus the bit-length of every value the instruction reads, computes, or writes (and, for indirect operands, the runtime address).

                      This is the crux of the model's soundness: every number the instruction touches is charged its bit-length, so a run of total log-cost T can only manipulate numbers of bit-length at most T. See the module docstring.

                      Equations
                      Instances For

                        The logarithmic cost of the machine's next step.

                        Equations
                        Instances For
                          def Complexity.RAM.run (P : Program) :
                          CfgCfg

                          Fuel-bounded run: execute up to fuel steps, stopping early once halted. Once halted, the configuration is stationary (run_halted), so the final configuration is independent of any fuel large enough to reach a halt.

                          Equations
                          Instances For

                            Accumulated logarithmic time over a fuel-bounded run: the sum of the per-step logarithmic costs of the non-halted steps taken.

                            Equations
                            Instances For

                              Accumulated unit time over a fuel-bounded run: simply the number of non-halted steps taken. Provided for contrast with logTimeUpto; the gap between the two is exactly what makes unit cost unsound (see the surface theorem RAM.logGap_squaring).

                              Equations
                              Instances For
                                noncomputable def Complexity.RAM.Cfg.space (c : Cfg) :

                                The logarithmic space content of a configuration: the total number of bits needed to name and store every nonzero register — for each nonzero register i, its address bits bitlen i plus its content bits bitlen (regs i). Registers holding 0 are free. The finsum is finite exactly when the register file has finite support, which is an invariant of every run started from initCfg (run_finiteSupport).

                                Equations
                                Instances For
                                  noncomputable def Complexity.RAM.spaceUpto (P : Program) :
                                  Cfg

                                  Peak logarithmic space over a fuel-bounded run: the maximum space content of any configuration visited (including the halted one).

                                  Equations
                                  Instances For

                                    The input convention. On input x : List Bool:

                                    • register 0 holds the length |x|;
                                    • register i + 1 holds bit x[i] (as 0/1) for i < |x|;
                                    • all other registers hold 0.

                                    Register 0 doubles as the accumulator/verdict register on output.

                                    Equations
                                    Instances For

                                      The initial configuration on input x: program counter 0, registers set by initRegs.

                                      Equations
                                      Instances For
                                        def Complexity.RAM.HaltsIn (P : Program) (c : Cfg) (fuel : ) :

                                        A program halts within fuel steps on c when the fuel-bounded run reaches a halted configuration.

                                        Equations
                                        Instances For

                                          A program halts on c when it halts within some amount of fuel.

                                          Equations
                                          Instances For

                                            The output of a decider: register 0 at halt. 1 means accept, 0 means reject.

                                            Equations
                                            Instances For

                                              P decides L within logarithmic time T(n): on every input x, the run halts having spent log-time at most T |x|, with verdict R₀ = 1 when x ∈ L and R₀ = 0 when x ∉ L. Mirrors TM.DecidesInTime.

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

                                                P decides L within logarithmic space S(n): on every input x, the run halts with the correct verdict and peak space at most S |x|. Mirrors TM.DecidesInSpace.

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