No public endorsements yet.
Loading review…
Sign in with ORCIDConcept map
Definition
A word RAM is a random access machine whose cells hold words: natural numbers below , for a word length that is a parameter of the model. It has a memory of cells, addressed by number, and no other storage. Input arrives on a read-only input tape and output is written on a write-only output tape. A program is a finite sequence of instructions, executed in order unless a jump instruction changes the program counter. Every instruction names the cells it works on: it sets a cell to a literal; it reads or writes a cell through the address held in another cell; it sets a cell to the sum, the difference, the product, the quotient, the bitwise conjunction or the left shift of two cells, or to the bitwise complement of one; it jumps unconditionally or if a cell is zero; it halts; or it reads the next input number into a cell or writes a cell to the output tape.
All arithmetic is arithmetic on words: every value the machine produces is taken modulo , and every address is taken modulo . Subtraction is truncated at zero rather than wrapping. Division is integer division, with .
The machine starts with all memory cells zero, the whole input word on the input tape and the output tape empty; it halts having written the output word. The running time is the number of instructions executed, each costing one time unit.
Lean source view on GitHub
| 1 | import Mathlib.Data.List.Basic |
| 2 | |
| 3 | /-! |
| 4 | --- |
| 5 | title: The word RAM |
| 6 | type: definition |
| 7 | --- |
| 8 | A word RAM is a random access machine whose cells hold *words*: natural |
| 9 | numbers below `2 ^ w`, for a word length `w` that is a parameter of the |
| 10 | model. It has a memory of `2 ^ w` cells, addressed by number, and no |
| 11 | other storage. Input arrives on a read-only input tape and output is |
| 12 | written on a write-only output tape. A program is a finite sequence of |
| 13 | instructions, executed in order unless a jump instruction changes the |
| 14 | program counter. Every instruction names the cells it works on: it sets |
| 15 | a cell to a literal; it reads or writes a cell through the address held |
| 16 | in another cell; it sets a cell to the sum, the difference, the product, |
| 17 | the quotient, the bitwise conjunction or the left shift of two cells, or |
| 18 | to the bitwise complement of one; it jumps unconditionally or if a cell |
| 19 | is zero; it halts; or it reads the next input number into a cell or |
| 20 | writes a cell to the output tape. |
| 21 | |
| 22 | All arithmetic is arithmetic on words: every value the machine produces |
| 23 | is taken modulo `2 ^ w`, and every address is taken modulo `2 ^ w`. |
| 24 | Subtraction is truncated at zero rather than wrapping. Division is |
| 25 | integer division, with `x / 0 = 0`. |
| 26 | |
| 27 | The machine starts with all memory cells zero, the whole input word on |
| 28 | the input tape and the output tape empty; it halts having written the |
| 29 | output word. The running time is the number of instructions executed, |
| 30 | each costing one time unit. |
| 31 | |
| 32 | # Formalization notes |
| 33 | |
| 34 | This is the machine the modern analysis of algorithms is stated on. Its |
| 35 | format is that of Cook and Reckhow (*Time bounded random access |
| 36 | machines*, JCSS 7, 1973): memory cells are the only storage, an |
| 37 | instruction is `cell ← f(cells)`, literals enter through one instruction |
| 38 | and indirection through two. Its numbers are bounded rather than its |
| 39 | instruction set, which is the discipline of Fredman and Willard |
| 40 | (*Surpassing the information theoretic bound with fusion trees*, JCSS |
| 41 | 47, 1993) and of Hagerup (*Sorting and searching on the word RAM*, |
| 42 | STACS 1998): cells hold `w`-bit words, `w` is large enough to address |
| 43 | the input — `w ≥ log n`, here always written as an explicit inequality |
| 44 | against `2 ^ w` at the point of use — and a word operation costs one |
| 45 | time unit because on words it is one instruction of a real machine. |
| 46 | Multiplication, division, bitwise operations and shifts are then |
| 47 | unproblematic, and this is what makes the model the one in which the |
| 48 | results of the algorithms literature are actually stated. The formats |
| 49 | in which those results are written down simulate one another with |
| 50 | constant overhead (van Emde Boas, *Machine models and simulations*, |
| 51 | Handbook of Theoretical Computer Science A, 1990, §2). |
| 52 | |
| 53 | Truncation is definitional and follows a single rule, applied |
| 54 | everywhere and with no exceptions: **every value the machine produces |
| 55 | is reduced modulo `2 ^ w` at the point of production, and every address |
| 56 | is reduced modulo `2 ^ w` at the point of use.** Values are produced |
| 57 | into memory, where `setCell` carries the reduction, and onto the output |
| 58 | tape, where `Instr.effect` writes it out; addresses are used by every |
| 59 | operand of every instruction, by the address `load` and `store` fetch |
| 60 | out of a cell, and by `setCell` when it writes. A literal is not |
| 61 | reduced where it is written down — that would be a second rule — but |
| 62 | the value it produces is, so an oversized literal is never observable |
| 63 | except through a word, and only a program's own literals can be |
| 64 | oversized in the first place, since every value it can read out of |
| 65 | memory is a word. Two consequences make the rule worth its uniformity: |
| 66 | every cell the machine can reach holds a word, by construction rather |
| 67 | than by an invariant to be proved; and the memory, although indexed by |
| 68 | all of `ℕ`, is touched only at the residues below `2 ^ w`, so it is |
| 69 | exactly the canonical `2 ^ w`-cell store. For the instructions whose |
| 70 | results cannot leave the words — truncated subtraction, division, |
| 71 | conjunction, complement — the reduction does nothing; it is written |
| 72 | anyway, because a rule without exceptions is easier to review than a |
| 73 | case distinction. |
| 74 | |
| 75 | Subtraction is natural-number monus, truncated at zero, so that a |
| 76 | comparison is `sub` followed by `jzero`. The complement is |
| 77 | `2 ^ w - 1 - m[b]`, the one value that depends on the word length other |
| 78 | than through truncation; with `and` and `shiftl` beside it, every |
| 79 | bitwise operation and both shifts take a number of instructions |
| 80 | independent of `w`. A program measures `w` itself, by counting the |
| 81 | doublings of a cell from `1` until it wraps to zero, so the model needs |
| 82 | no instruction reporting the word length and one program serves every |
| 83 | word length. The remaining standard operations are derived at constant |
| 84 | cost; with `t` and `u` cells the program spares: |
| 85 | |
| 86 | | operation | instructions | count | |
| 87 | |---|---|---| |
| 88 | | copy `a ← b` | `set t b; load a t` | 2 | |
| 89 | | `a ← b ∨ c` | `and t b c; sub t c t; add a b t` | 3 | |
| 90 | | `a ← b ⊕ c` | `and t b c; sub u c t; add u b u; sub a u t` | 4 | |
| 91 | | `a ← b ≫ c` | `set t 1; shiftl t t c; div a b t` | 3 | |
| 92 | | `a ← b mod c` | `div t b c; mul t t c; sub a b t` | 3 | |
| 93 | | if `b ≤ c` goto `l` | `sub t b c; jzero t l` | 2 | |
| 94 | | if `b < c` goto `l` | `sub t c b; jzero t l'; jump l; l':` | 3 | |
| 95 | | if `b = c` goto `l` | `sub t b c; sub u c b; add t t u; jzero t l` | 4 | |
| 96 | |
| 97 | `read` reduces the number it takes off the input tape modulo `2 ^ w`, |
| 98 | like every other value, so the machine is total in its input and |
| 99 | honesty about inputs whose entries do not fit into a word lives on the |
| 100 | statement side, in the set of admissible inputs a claim quantifies |
| 101 | over. |
| 102 | |
| 103 | Reading and writing are total: a `halt` instruction halts the machine, |
| 104 | an out-of-range program counter halts it, a read from an exhausted |
| 105 | input tape halts it, and every memory cell holds a number, so no error |
| 106 | states are needed. `Instr.effect` is the whole of the instruction |
| 107 | semantics and `step` adds only the fetch, returning `none` exactly when |
| 108 | the machine has halted, so the semantics is deterministic and total by |
| 109 | construction. `run w p t` is `t`-fold application of `step`, and it is |
| 110 | `none` as soon as the machine halts, which is what makes "halts after |
| 111 | exactly `t` steps" in `RunsTo` a statement about the *number of |
| 112 | instructions executed*: the time measure is intrinsic to the machine |
| 113 | and is not an annotation carried alongside the program. `RunsTo` |
| 114 | constrains the output tape and nothing else: memory is scratch space |
| 115 | and is left unconstrained on halting. |
| 116 | |
| 117 | The input and output tapes are what makes the machine's memory start |
| 118 | out empty, and hence what lets a program address it by fixed cell |
| 119 | numbers; an input laid out in memory instead would begin at a cell |
| 120 | number depending on the input length. A program that wants random |
| 121 | access to its input copies it into memory first, at a cost of one |
| 122 | instruction per number. |
| 123 | |
| 124 | Time is the machine's own step count, one unit per instruction, and it |
| 125 | is honest for multiplication precisely because the factors are words. |
| 126 | There is no space measure: it would be a further definition over `run`, |
| 127 | and space is in any case bounded by the `2 ^ w` cells the machine can |
| 128 | address. Randomness is absent as well; a randomized program is a |
| 129 | deterministic program that consumes a word list of random numbers, |
| 130 | which is definable downstream over this same machine, with no change to |
| 131 | the model. |
| 132 | -/ |
| 133 | |
| 134 | namespace Lax13.Ram |
| 135 | |
| 136 | /-- An instruction. The first cell named is the one written, and every |
| 137 | other number naming a cell is read; `set` is the only instruction |
| 138 | carrying a literal, and `jump`, `jzero` carry a program address. -/ |
| 139 | inductive Instr |
| 140 | /-- Set cell `a` to the literal `n`. -/ |
| 141 | | set (a n : ℕ) |
| 142 | /-- Set cell `a` to the contents of the cell whose address cell `b` |
| 143 | holds. -/ |
| 144 | | load (a b : ℕ) |
| 145 | /-- Set the cell whose address cell `a` holds to the contents of cell |
| 146 | `b`. -/ |
| 147 | | store (a b : ℕ) |
| 148 | /-- Set cell `a` to the sum of cells `b` and `c`, wrapping around |
| 149 | modulo `2 ^ w`. -/ |
| 150 | | add (a b c : ℕ) |
| 151 | /-- Set cell `a` to the difference of cells `b` and `c`, truncated at |
| 152 | zero rather than wrapping around. -/ |
| 153 | | sub (a b c : ℕ) |
| 154 | /-- Set cell `a` to the product of cells `b` and `c`, wrapping around |
| 155 | modulo `2 ^ w`. -/ |
| 156 | | mul (a b c : ℕ) |
| 157 | /-- Set cell `a` to the quotient of cells `b` and `c`, rounding |
| 158 | towards zero; division by zero yields zero. -/ |
| 159 | | div (a b c : ℕ) |
| 160 | /-- Set cell `a` to the bitwise conjunction of cells `b` and `c`. -/ |
| 161 | | and (a b c : ℕ) |
| 162 | /-- Set cell `a` to cell `b` shifted left by the number of bits cell |
| 163 | `c` holds, wrapping around modulo `2 ^ w`; a shift by `w` or more |
| 164 | yields zero. -/ |
| 165 | | shiftl (a b c : ℕ) |
| 166 | /-- Set cell `a` to the bitwise complement `2 ^ w - 1 - m[b]` of cell |
| 167 | `b` within the word length. -/ |
| 168 | | not (a b : ℕ) |
| 169 | /-- Continue at instruction `l`. -/ |
| 170 | | jump (l : ℕ) |
| 171 | /-- Continue at instruction `l` if cell `a` is zero. -/ |
| 172 | | jzero (a l : ℕ) |
| 173 | /-- Halt. -/ |
| 174 | | halt |
| 175 | /-- Read the next number of the input tape into cell `a`, or halt if |
| 176 | the tape is exhausted. -/ |
| 177 | | read (a : ℕ) |
| 178 | /-- Append the contents of cell `a` to the output tape. -/ |
| 179 | | write (a : ℕ) |
| 180 | |
| 181 | /-- A program: a finite sequence of instructions, numbered from `0`. -/ |
| 182 | abbrev Program : Type := List Instr |
| 183 | |
| 184 | /-- A machine state: the program counter, the contents of every memory |
| 185 | cell, the part of the input tape not yet read, and the output tape |
| 186 | written so far. Memory is the only storage there is. -/ |
| 187 | structure State where |
| 188 | /-- The number of the instruction to be executed next. -/ |
| 189 | pc : ℕ |
| 190 | /-- The contents of the memory cells; only the cells with number below |
| 191 | `2 ^ w` are ever addressed. -/ |
| 192 | mem : ℕ → ℕ |
| 193 | /-- The numbers still to be read from the input tape. -/ |
| 194 | inp : List ℕ |
| 195 | /-- The numbers written to the output tape so far. -/ |
| 196 | out : List ℕ |
| 197 | |
| 198 | /-- The memory `m` with cell `a` set to `v`, at word length `w`: the |
| 199 | address and the value written are both taken modulo `2 ^ w`. -/ |
| 200 | def setCell (w : ℕ) (m : ℕ → ℕ) (a v : ℕ) : ℕ → ℕ := |
| 201 | fun b => if b = a % 2 ^ w then v % 2 ^ w else m b |
| 202 | |
| 203 | /-- The effect of one instruction on the state at word length `w`, or |
| 204 | `none` if it halts the machine, which a `halt` instruction and a read |
| 205 | from an exhausted input tape do. Every value produced is reduced modulo |
| 206 | `2 ^ w` and every address used is reduced modulo `2 ^ w`. -/ |
| 207 | def Instr.effect (w : ℕ) : Instr → State → Option State |
| 208 | | set a n, s => some { s with pc := s.pc + 1, mem := setCell w s.mem a n } |
| 209 | | load a b, s => |
| 210 | some |
| 211 | { s with |
| 212 | pc := s.pc + 1 |
| 213 | mem := setCell w s.mem a (s.mem (s.mem (b % 2 ^ w) % 2 ^ w)) } |
| 214 | | store a b, s => |
| 215 | some |
| 216 | { s with |
| 217 | pc := s.pc + 1 |
| 218 | mem := setCell w s.mem (s.mem (a % 2 ^ w)) (s.mem (b % 2 ^ w)) } |
| 219 | | add a b c, s => |
| 220 | some |
| 221 | { s with |
| 222 | pc := s.pc + 1 |
| 223 | mem := setCell w s.mem a (s.mem (b % 2 ^ w) + s.mem (c % 2 ^ w)) } |
| 224 | | sub a b c, s => |
| 225 | some |
| 226 | { s with |
| 227 | pc := s.pc + 1 |
| 228 | mem := setCell w s.mem a (s.mem (b % 2 ^ w) - s.mem (c % 2 ^ w)) } |
| 229 | | mul a b c, s => |
| 230 | some |
| 231 | { s with |
| 232 | pc := s.pc + 1 |
| 233 | mem := setCell w s.mem a (s.mem (b % 2 ^ w) * s.mem (c % 2 ^ w)) } |
| 234 | | div a b c, s => |
| 235 | some |
| 236 | { s with |
| 237 | pc := s.pc + 1 |
| 238 | mem := setCell w s.mem a (s.mem (b % 2 ^ w) / s.mem (c % 2 ^ w)) } |
| 239 | | and a b c, s => |
| 240 | some |
| 241 | { s with |
| 242 | pc := s.pc + 1 |
| 243 | mem := setCell w s.mem a (Nat.land (s.mem (b % 2 ^ w)) (s.mem (c % 2 ^ w))) } |
| 244 | | shiftl a b c, s => |
| 245 | some |
| 246 | { s with |
| 247 | pc := s.pc + 1 |
| 248 | mem := setCell w s.mem a (s.mem (b % 2 ^ w) * 2 ^ s.mem (c % 2 ^ w)) } |
| 249 | | not a b, s => |
| 250 | some |
| 251 | { s with |
| 252 | pc := s.pc + 1 |
| 253 | mem := setCell w s.mem a (2 ^ w - 1 - s.mem (b % 2 ^ w)) } |
| 254 | | jump l, s => some { s with pc := l } |
| 255 | | jzero a l, s => some { s with pc := if s.mem (a % 2 ^ w) = 0 then l else s.pc + 1 } |
| 256 | | halt, _ => none |
| 257 | | read a, s => |
| 258 | s.inp.head?.map fun v => |
| 259 | { s with pc := s.pc + 1, mem := setCell w s.mem a v, inp := s.inp.tail } |
| 260 | | write a, s => |
| 261 | some { s with pc := s.pc + 1, out := s.out ++ [s.mem (a % 2 ^ w) % 2 ^ w] } |
| 262 | |
| 263 | /-- One step of the machine at word length `w`: fetch the instruction |
| 264 | the program counter points at and execute it. The result is `none` if |
| 265 | the machine has halted, which also happens when the program counter has |
| 266 | run past the program. -/ |
| 267 | def step (w : ℕ) (p : Program) (s : State) : Option State := |
| 268 | p[s.pc]?.bind fun i => i.effect w s |
| 269 | |
| 270 | /-- The state after `t` steps at word length `w`, or `none` if the |
| 271 | machine halts before executing `t` instructions. -/ |
| 272 | def run (w : ℕ) (p : Program) : ℕ → State → Option State |
| 273 | | 0, s => some s |
| 274 | | t + 1, s => (step w p s).bind (run w p t) |
| 275 | |
| 276 | /-- The initial state on input `x`: program counter zero, all memory |
| 277 | cells zero, the input word on the input tape, the output tape empty. -/ |
| 278 | def initState (x : List ℕ) : State where |
| 279 | pc := 0 |
| 280 | mem := fun _ => 0 |
| 281 | inp := x |
| 282 | out := [] |
| 283 | |
| 284 | /-- Started on input `x` at word length `w`, the machine executes |
| 285 | exactly `t` instructions and then halts, having written the word `y` to |
| 286 | its output tape. -/ |
| 287 | def RunsTo (w : ℕ) (p : Program) (x y : List ℕ) (t : ℕ) : Prop := |
| 288 | ∃ s : State, run w p t (initState x) = some s ∧ step w p s = none ∧ s.out = y |
| 289 | |
| 290 | end Lax13.Ram |
| 291 |
Formalization notes
This is the machine the modern analysis of algorithms is stated on. Its format is that of Cook and Reckhow (Time bounded random access machines, JCSS 7, 1973): memory cells are the only storage, an instruction is , literals enter through one instruction and indirection through two. Its numbers are bounded rather than its instruction set, which is the discipline of Fredman and Willard (Surpassing the information theoretic bound with fusion trees, JCSS 47, 1993) and of Hagerup (Sorting and searching on the word RAM, STACS 1998): cells hold -bit words, is large enough to address the input — , here always written as an explicit inequality against at the point of use — and a word operation costs one time unit because on words it is one instruction of a real machine. Multiplication, division, bitwise operations and shifts are then unproblematic, and this is what makes the model the one in which the results of the algorithms literature are actually stated. The formats in which those results are written down simulate one another with constant overhead (van Emde Boas, Machine models and simulations, Handbook of Theoretical Computer Science A, 1990, §2).
Truncation is definitional and follows a single rule, applied everywhere and with no exceptions: every value the machine produces is reduced modulo at the point of production, and every address is reduced modulo at the point of use. Values are produced into memory, where carries the reduction, and onto the output tape, where writes it out; addresses are used by every operand of every instruction, by the address and fetch out of a cell, and by when it writes. A literal is not reduced where it is written down — that would be a second rule — but the value it produces is, so an oversized literal is never observable except through a word, and only a program's own literals can be oversized in the first place, since every value it can read out of memory is a word. Two consequences make the rule worth its uniformity: every cell the machine can reach holds a word, by construction rather than by an invariant to be proved; and the memory, although indexed by all of , is touched only at the residues below , so it is exactly the canonical -cell store. For the instructions whose results cannot leave the words — truncated subtraction, division, conjunction, complement — the reduction does nothing; it is written anyway, because a rule without exceptions is easier to review than a case distinction.
Subtraction is natural-number monus, truncated at zero, so that a comparison is followed by . The complement is , the one value that depends on the word length other than through truncation; with and beside it, every bitwise operation and both shifts take a number of instructions independent of . A program measures itself, by counting the doublings of a cell from until it wraps to zero, so the model needs no instruction reporting the word length and one program serves every word length. The remaining standard operations are derived at constant cost; with and cells the program spares:
| operation | instructions | count |
|---|---|---|
| copy | 2 | |
| 3 | ||
| 4 | ||
| 3 | ||
| 3 | ||
| if goto | 2 | |
| if goto | 3 | |
| if goto | 4 |
reduces the number it takes off the input tape modulo , like every other value, so the machine is total in its input and honesty about inputs whose entries do not fit into a word lives on the statement side, in the set of admissible inputs a claim quantifies over.
Reading and writing are total: a instruction halts the machine, an out-of-range program counter halts it, a read from an exhausted input tape halts it, and every memory cell holds a number, so no error states are needed. is the whole of the instruction semantics and adds only the fetch, returning exactly when the machine has halted, so the semantics is deterministic and total by construction. is -fold application of , and it is as soon as the machine halts, which is what makes "halts after exactly steps" in a statement about the number of instructions executed: the time measure is intrinsic to the machine and is not an annotation carried alongside the program. constrains the output tape and nothing else: memory is scratch space and is left unconstrained on halting.
The input and output tapes are what makes the machine's memory start out empty, and hence what lets a program address it by fixed cell numbers; an input laid out in memory instead would begin at a cell number depending on the input length. A program that wants random access to its input copies it into memory first, at a cost of one instruction per number.
Time is the machine's own step count, one unit per instruction, and it is honest for multiplication precisely because the factors are words. There is no space measure: it would be a further definition over , and space is in any case bounded by the cells the machine can address. Randomness is absent as well; a randomized program is a deterministic program that consumes a word list of random numbers, which is definable downstream over this same machine, with no change to the model.
Builds on
none
From Mathlib
Community review
Discussion
Ask a question or add context. Endorsements and structured flags are kept in the review panel above; your ORCID profile must share a public name.
0 comments