Multitape Turing machines and exact integer multiplication in time
DefinitionIntMul_MultitapeModelThis file fixes the machine model and the multiplication task shared by the integer-multiplication missions. The machine conventions are those of Montanaro's Computational Complexity lecture notes (§3, §3.4). The task is the one stated in Harvey–van der Hoeven and in the OpenAI preprint.
A -tape Turing machine consists of the following:
- A finite alphabet containing the blank , the start symbol , and symbols . These five symbols are pairwise distinct.
- A finite set of states with a start state and a halting state .
- tapes: tape is the input tape, tape is the output tape, and the other tapes are work tapes. Each tape is infinite in one direction, with cells and in cell .
- A transition function
In one step, the machine reads the scanned symbols, overwrites each scanned cell, moves each head by at most one cell, and changes state.
The transition function satisfies four conditions:
- On a cell holding , the machine writes back and does not move left.
- The machine never writes on a cell that does not hold it, so occurs only in cell of each tape.
- , so a halted machine never changes again.
- The input tape is read-only.
For , written most significant bit first, is the integer that represents, and is the binary representation of padded on the left with zeros to length . Put .
The machine is started in with the input tape holding , every other tape holding , and every head on cell . It multiplies -bit integers within steps if, for all , it reaches within steps and the output tape then holds exactly
Multiplication is possible in time , written , if there is one machine that halts with the correct output on input for every and all , and whose worst-case running time satisfies for all , for some constants and . Finally,
These definitions express the main theorems of Harvey–van der Hoeven () and of the OpenAI preprint and its follow-ups () as statements about one common object.
Formalization Note Following the papers, the size parameter is the length of each operand, not the input length , and only well-formed inputs with are constrained. The two inputs are separated by , as in the papers; the notes use a comma for the same purpose. A left move from cell cannot occur, because cell always holds . Since freezes the configuration, "in state after some steps" is the same as "halts using at most steps".
import Mathlib
/-!
# Exact integer multiplication on deterministic multitape Turing machines
Shared model for the integer-multiplication complexity missions.
Machine conventions follow A. Montanaro, *Computational Complexity* lecture notes
(Cambridge, 2012), §3 (Turing machines), §3.4 (multiple-tape machines), §3.3 (big-O),
§4 (time-bounded computation). The multiplication task follows Harvey–van der Hoeven 2021, §1,
and OpenAI, *Integer multiplication below n log n*, §1.
-/
namespace IntMul
/-- Head movements `←`, `−`, `→`. -/
inductive Move
| left
| stay
| right
deriving DecidableEq
/-- A deterministic `k`-tape Turing machine (Montanaro §3, §3.4).
* `Σ` is a finite alphabet containing the blank `□`, the start symbol `▷`, and the symbols
`0`, `1`, `#` used for the input and output; these five symbols are pairwise distinct.
* `K` is a finite set of states with a start state `START` and a halting state `HALT ≠ START`.
* There are `k ≥ 2` tapes: tape `0` is the input tape, tape `1` is the output tape, and the
remaining `k - 2` tapes are work tapes. Every tape is infinite in one direction (cells
`0, 1, 2, …`), with cell `0` holding `▷`.
* `δ : K × Σᵏ → K × (Σ × {←, −, →})ᵏ` is the transition function.
The conditions are those of the notes: on a cell holding `▷` the machine rewrites `▷` and does
not move left; `▷` is never written anywhere else, so it occurs only in cell `0` of each tape;
in state `HALT` the configuration no longer changes; and the input tape is read-only. -/
structure MultitapeTM where
/-- the alphabet `Σ` -/
Sym : Type
[instFintypeSym : Fintype Sym]
/-- the blank symbol `□` -/
blank : Sym
/-- the start symbol `▷` -/
startSym : Sym
/-- the symbol for the bit `0` -/
zero : Sym
/-- the symbol for the bit `1` -/
one : Sym
/-- the separator `#` between the two inputs -/
sep : Sym
syms_distinct : [blank, startSym, zero, one, sep].Nodup
/-- the set of states `K` -/
K : Type
[instFintypeK : Fintype K]
/-- the start state `START` -/
qStart : K
/-- the halting state `HALT` -/
qHalt : K
start_ne_halt : qStart ≠ qHalt
/-- the number of tapes -/
k : ℕ
two_le_k : 2 ≤ k
/-- the transition function `δ : K × Σᵏ → K × (Σ × {←, −, →})ᵏ` -/
δ : K → (Fin k → Sym) → K × (Fin k → Sym × Move)
/-- the head never erases `▷` and never moves left from it -/
start_preserved : ∀ q a i, a i = startSym →
((δ q a).2 i).1 = startSym ∧ ((δ q a).2 i).2 ≠ Move.left
/-- `▷` is never written on a cell that does not already hold it, so `▷` stays at the start
of each tape only -/
start_only_at_start : ∀ q a i, a i ≠ startSym → ((δ q a).2 i).1 ≠ startSym
/-- `δ(HALT, σ) = (HALT, σ, −)`: once halted, the machine no longer changes its configuration -/
halt_fixed : ∀ a, δ qHalt a = (qHalt, fun i => (a i, Move.stay))
/-- the input tape is read-only -/
input_readonly : ∀ q a, ((δ q a).2 ⟨0, by omega⟩).1 = a ⟨0, by omega⟩
attribute [instance] MultitapeTM.instFintypeSym MultitapeTM.instFintypeK
namespace MultitapeTM
variable (M : MultitapeTM)
/-- The input tape (tape `0`). -/
def inTape : Fin M.k := ⟨0, by have := M.two_le_k; omega⟩
/-- The output tape (tape `1`). -/
def outTape : Fin M.k := ⟨1, by have := M.two_le_k; omega⟩
/-- A configuration: the current state, the contents of every tape (cell `p` of tape `i` is
`cells i p`), and the position of every head. -/
structure Cfg where
state : M.K
cells : Fin M.k → ℕ → M.Sym
head : Fin M.k → ℕ
/-- One step: with state `q` and scanned symbols `a`, if `δ(q, a) = (q', (σᵢ, dᵢ)ᵢ)` then each
tape `i` has the scanned cell overwritten by `σᵢ`, its head moves according to `dᵢ`, and the
state becomes `q'`. -/
def step (c : M.Cfg) : M.Cfg :=
let r := M.δ c.state (fun i => c.cells i (c.head i))
{ state := r.1
cells := fun i => Function.update (c.cells i) (c.head i) (r.2 i).1
head := fun i =>
match (r.2 i).2 with
| Move.left => c.head i - 1
| Move.stay => c.head i
| Move.right => c.head i + 1 }
/-- Encoding of a bit as a symbol. -/
def bitSym (b : Bool) : M.Sym := if b then M.one else M.zero
/-- Tape contents `▷ w □ □ …`: `▷` in cell `0`, the symbols of `w` in cells `1, …, |w|`, and
blanks everywhere after. -/
def tapeOf (w : List M.Sym) : ℕ → M.Sym
| 0 => M.startSym
| p + 1 => w.getD p M.blank
/-- The initial configuration on input `x#y`: state `START`; the input tape holds
`▷ x # y □ □ …`; every other tape holds `▷ □ □ …`; every head is on cell `0`. -/
def initCfg (x y : List Bool) : M.Cfg where
state := M.qStart
cells := fun i =>
if i = M.inTape then M.tapeOf (x.map M.bitSym ++ M.sep :: y.map M.bitSym)
else M.tapeOf []
head := fun _ => 0
/-- On input `x#y`, after `t` steps the machine is in state `HALT` and the output tape holds
exactly `▷ w □ □ …` (output `w`). Since `HALT` freezes the configuration, this holds for some
`t ≤ T` iff the machine halts with output `w` using at most `T` steps. -/
def HaltsWithOutput (x y : List Bool) (t : ℕ) (w : List Bool) : Prop :=
(M.step^[t] (M.initCfg x y)).state = M.qHalt ∧
(M.step^[t] (M.initCfg x y)).cells M.outTape = M.tapeOf (w.map M.bitSym)
end MultitapeTM
/-- `val x`: the nonnegative integer whose binary representation is `x`,
leftmost bit most significant (`val [] = 0`). -/
def val (x : List Bool) : ℕ :=
x.foldl (fun a b => 2 * a + b.toNat) 0
/-- `bin k z`: the binary representation of `z` padded on the left to length `k`
(most significant bit first). Meaningful for `z < 2 ^ k`. -/
def bin (k z : ℕ) : List Bool :=
List.ofFn fun i : Fin k => z.testBit (k - 1 - i)
/-- `lg n = max (⌈log₂ n⌉, 1)`. -/
def lg (n : ℕ) : ℕ := max (Nat.clog 2 n) 1
/-- `M` multiplies `n`-bit integers within `T(n)` steps: for all `x, y ∈ {0,1}ⁿ`, on input
`x#y` the machine halts with output `bin_{2n}(val x · val y)` using at most `T(n)` steps. -/
def MultipliesAt (M : MultitapeTM) (n : ℕ) (T : ℝ) : Prop :=
∀ x y : List Bool, x.length = n → y.length = n →
∃ t : ℕ, (t : ℝ) ≤ T ∧ M.HaltsWithOutput x y t (bin (2 * n) (val x * val y))
/-- Exact integer multiplication is possible in time `O(g(n))` (Montanaro §3.3, §4): there is a
single machine `M` that, for every `n ≥ 1` and all `x, y ∈ {0,1}ⁿ`, halts on input `x#y` with
output `bin_{2n}(val x · val y)`, and whose worst-case running time `T(n)` satisfies
`T(n) ≤ c · g(n)` for all `n ≥ n₀`, for some constant `c > 0` and some `n₀`. -/
def MulTimeBound (g : ℕ → ℝ) : Prop :=
∃ M : MultitapeTM,
(∀ n : ℕ, 1 ≤ n → ∃ T : ℝ, MultipliesAt M n T) ∧
∃ c : ℝ, 0 < c ∧ ∃ n₀ : ℕ, ∀ n : ℕ, n₀ ≤ n → 1 ≤ n → MultipliesAt M n (c * g n)
/-- Multiplication in time `O(n (lg n)^{1-κ})`. -/
def KappaBound (κ : ℝ) : Prop :=
MulTimeBound fun n => (n : ℝ) * ((lg n : ℝ) ^ (1 - κ))
end IntMul
Read-back
What the Lean code literally says, in plain math · claude-opus-5-5
Read-back: Def_IntMul_MultitapeModel (namespace IntMul)
The file depends only on Mathlib. It defines a model of deterministic multitape Turing machines, together with what it means for one of them to multiply -bit integers within a step budget. The declarations are described below in source order.
1. Move
There are three possible head movements: left, stay and right. Equality between them is decidable.
2. MultitapeTM: a deterministic -tape machine
A machine consists of the following data and conditions.
- Alphabet. A type , assumed finite (a
Fintypeinstance), with five named symbols: the blank , the start symbol , the bit symbols and , and the separator . The only condition is that these five are pairwise distinct. may contain any finite number of further symbols, which can serve as work symbols. - States. A finite type with a start state and a halting state , where . No other states are named, and nothing else is required of .
- Tapes. A natural number with . Each machine has its own fixed . Tapes are indexed by .
- Transition function. A total function
For , the value is the symbol written on tape and is the move of head .
The following conditions are imposed for every state (including ), every scanned tuple and every tape :
- (start symbol preserved) If , then and .
- (start symbol never newly written) If , then .
- (halt is frozen) For every , . In the halting state the machine rewrites every scanned symbol unchanged and does not move any head.
- (input tape read-only) For every and , : tape always gets back the symbol it scanned. The head on tape may still move freely.
Conditions 1 and 2 together say that writes on a tape exactly when that tape scans . No condition restricts the output tape (for example, it is not write-only), the work tapes, the symbols written on tapes other than , or the moves of the heads, apart from the ban on moving left from a . Conditions 1–4 are mutually consistent, so such machines exist.
3. inTape and outTape
The input tape is tape and the output tape is tape . Both exist because . Tapes have no designated role.
4. Cfg: configurations
A configuration of is a triple :
- is the current state;
- gives the contents, with the symbol in cell of tape ;
- gives the head positions.
Each tape is one-way infinite, with cells . A configuration as such is completely unconstrained: tape contents are arbitrary functions, need not be blank from some point on, and may hold anywhere. The constraints below come only from reachability from the initial configuration.
5. step: one computation step
From , let be the scanned symbols and let . The next configuration is , where
Here is truncated subtraction on . So a head at cell that is told to move left stays at cell ; this is not an error. In configurations reachable from an initial configuration (see items 8 and 9) this case never arises. There, cell of every tape always holds , and condition 1 forbids moving left from .
step is a total function. It is applied the same way in every state. Because of condition 3, a configuration in state is a fixed point of step: the scanned cells are rewritten with their own contents and no head moves.
6. bitSym
Booleans are encoded as symbols: and . For a bit list , write for its symbol list.
7. tapeOf
For a finite symbol list , the tape contents are
So . The empty list gives .
8. initCfg: the initial configuration on
For bit lists and of any lengths, possibly different and possibly empty, the initial configuration has:
- state ;
- input tape ;
- every other tape (the output tape and all work tapes) equal to ;
- every head at cell .
For the input tape is .
Where can appear. In the initial configuration, is in cell of every tape and nowhere else, because are all distinct from . A step changes only the scanned cells. By conditions 1–2, a scanned is rewritten as and a scanned non- is never turned into . Hence every configuration reachable from initCfg has in exactly cell of each tape. This is a consequence of the definitions; the file does not state it as a lemma. In arbitrary, non-reachable configurations, can appear anywhere.
9. HaltsWithOutput
For bit lists and , let denote applications of step, with the identity. The predicate holds iff the configuration
satisfies both of the following:
- its state is ; and
- its entire output tape (tape ) equals . That is, cell holds , cells hold the bits of as symbols, and every later cell holds . No leftover non-blank symbols are allowed anywhere on tape .
The predicate does not constrain:
- the position of the output head or of any other head;
- the contents of the input tape or of the work tapes;
- whether is the first time the state is .
Because halted configurations are fixed points, if the predicate holds at it also holds at every . Hence "it holds for some " is the same as "the machine reaches within steps with this output tape". Here counts applications of the step function, and the step that enters is counted. Since , the predicate fails at , so is necessary.
10. val
For a bit list , the value is
with the most significant bit first. It is computed by folding from . Leading zeros are allowed and . Every of length has .
11. bin
For , is the length- bit list whose -th entry () is bit number of , where bit is the least significant. It is therefore the binary representation of
padded with leading zeros to exactly bits, most significant bit first. If , the higher bits are silently dropped. is the empty list.
12. lg
For ,
Here is Mathlib's Nat.clog 2 n, the least with , which is for . So , , , and so on. In every case .
13. MultipliesAt
For a machine , and a real number , the predicate holds iff:
Since , the required output is exactly the product written with exactly bits, including leading zeros, and no truncation occurs.
- The predicate quantifies only over inputs where both and have length exactly . Behaviour on unequal lengths is unconstrained.
- The bound is a comparison of the natural number with a real, so it is equivalent to .
- If , the predicate is false for , because is needed and there is at least one input.
- For the only input is , and the required output is , so the output tape must be .
14. MulTimeBound
For , holds iff:
The machine. One single machine , with fixed alphabet, state set and tape count , must work for all .
First conjunct. For every , correctly multiplies all pairs of -bit inputs and halts within some finite real bound that may depend on . Since there are finitely many inputs of length , this amounts to: halts on every with , and its output tape is then exactly . This conjunct is what forces correctness for , which the second conjunct does not cover. It imposes no time bound.
Second conjunct. There are a real constant and a threshold . Both are chosen after , and neither depends on . For every and every pair of length , reaches with the correct output tape within at most steps.
What is not constrained. Inputs with are never constrained. Inputs with are never constrained. Nothing is required of itself. If for infinitely many (for example, if infinitely often), the second conjunct is unsatisfiable.
15. KappaBound
For a real , with no restriction on its sign or size,
The power is the real power. Since , the base is a positive real and for all . At the function equals .
- gives .
- gives .
- gives , which grows more slowly than .
- gives exponents larger than .
Unfolded, the statement is: there exist one machine , a constant and an as in item 14. correctly multiplies all pairs of -bit inputs for every . For every it does so within steps on every such pair.
Confirmed by the mission captain (proposal self-audit).
Confirmed by the moderator at approval.