Blum–Shub–Smale machines over
DefinitionSmaleNinth_BSSMachineA machine over the real numbers, in the sense of Blum, Shub and Smale, is the model of computation in which exact real arithmetic is available at unit cost. This module fixes one concrete such model.
Configurations. The memory is a tape, a bi-infinite family of real registers indexed by the integers, written with . A configuration is a pair consisting of a program counter and a tape.
Programs. A program is a finite list of instructions, each of one of the following kinds, where the addresses are fixed inside the instruction:
- , loading a machine constant , which may be an arbitrary real number;
- for , an exact field operation on two registers;
- a left shift replacing the tape by , and a right shift replacing it by ;
- a sign-test branch: if set the counter to a fixed target, otherwise advance it by one;
- the two halting instructions and .
Every non-branching, non-halting instruction advances the counter by one. The shifts are what give a finite list of instructions, whose addresses are hard-coded, access to unboundedly many registers.
Execution and cost. One step executes the instruction at the current counter; a configuration whose counter carries , carries , or points past the end of the program is a fixed point, so execution simply stalls there. Running a program on an initial tape means iterating this step from counter . A program decides in time with verdict if for some the configuration after exactly steps has its counter on (when is true) or on (when is false). Cost is the number of executed instructions: one unit per arithmetic operation, constant load, shift, or comparison, irrespective of the magnitude of the reals involved. This is the point of the model — no bit lengths enter the accounting.
Input convention for linear systems. An instance of linear feasibility, given by and , is presented on the tape as: cell holds , cell holds , cells hold the entries of in row-major order, cells hold , and every remaining cell — including every negative one — holds . The instance therefore occupies cells, the quantity in which running times are measured.
Conventions and their cost. Division is totalized as and the branch test is the non-strict ; both are harmless, since a program may guard divisions by sign tests at no asymptotic cost. Halting requires the counter to rest on an actual halting instruction: running off the end of the program is not a verdict. Crucially, a program is a single finite list with no dependence on or , so any statement quantifying over programs quantifies over uniform algorithms; non-uniform families of decision trees, one per input size, are not expressible here, and it is exactly this restriction that makes polynomial-time questions in this model nontrivial.
import Mathlib.Data.Real.Basic
import Mathlib.Data.Matrix.Mul
import Mathlib.Logic.Function.Iterate
/-!
A register machine over the real numbers (Blum–Shub–Smale style), with
unit-cost exact real arithmetic — the model in which Smale poses his 9th
problem.
Source: S. Smale, *Mathematical problems for the next century*, Mathematical
Intelligencer 20(2):7–15, 1998, Problem 9: "Is there a polynomial-time
algorithm over the real numbers which decides the feasibility of the linear
system of inequalities $Ax \ge b$?" — where "algorithm over the real
numbers" is the machine model of L. Blum, M. Shub, S. Smale, *On a theory of
computation and complexity over the real numbers*, Bull. AMS 21(1):1–46,
1989.
The model formalized here:
- The machine state is a program counter together with a **bi-infinite tape**
`ℤ → ℝ` of real registers (the state space `ℝ_∞` of BSS §1; a bi-infinite
tape with two-sided shifts is the standard presentation giving full
Turing-style access to unboundedly many registers).
- A program is a finite list of instructions. Arithmetic instructions
(`const`, `add`, `sub`, `mul`, `div`) act on tape cells at **fixed**
addresses hard-coded in the instruction — together with the two shift
instructions this yields exactly the BSS computation nodes (rational maps
with built-in real machine constants, applied in a finite window that the
shifts move along the tape). `jle i target` is the BSS branch node
(branch on the sign test `x_i ≤ 0`); `accept` / `reject` are output nodes.
- Division is Lean-total (`x / 0 = 0`), a benign totalization: a genuine BSS
machine can guard every division by a sign test at no asymptotic cost.
- **Cost = number of executed instructions** (unit cost per arithmetic
operation, comparison, or shift — the algebraic/arithmetic complexity
measure). The input is `k` real numbers laid out in tape cells `0, …, k−1`;
"polynomial time" means a step count polynomial in `k`.
`encodeLP` fixes the input convention for the LP feasibility problem: for an
`m × n` system `Ax ≥ b`, the tape holds `m` and `n` (as reals) in cells
`0, 1`, the entries of `A` row-major in cells `2, …, mn+1`, and `b` in cells
`mn+2, …, mn+m+1`; all other cells are `0`.
-/
namespace SmaleNinth
/-- An instruction of a BSS register machine over `ℝ`: real-constant loads,
field arithmetic on fixed tape addresses, two-sided tape shifts, a sign-test
branch, and the two output instructions. -/
inductive BSSInstr : Type
/-- `x[dst] := c` — load a machine constant (an arbitrary real, per BSS). -/
| const (dst : ℤ) (c : ℝ)
/-- `x[dst] := x[i] + x[j]`. -/
| add (dst i j : ℤ)
/-- `x[dst] := x[i] − x[j]`. -/
| sub (dst i j : ℤ)
/-- `x[dst] := x[i] * x[j]`. -/
| mul (dst i j : ℤ)
/-- `x[dst] := x[i] / x[j]` (Lean-total: division by zero yields `0`). -/
| div (dst i j : ℤ)
/-- Shift the whole tape one cell to the left: new `x[k] = ` old `x[k+1]`. -/
| shiftL
/-- Shift the whole tape one cell to the right: new `x[k] = ` old `x[k−1]`. -/
| shiftR
/-- If `x[i] ≤ 0` jump to instruction `target`, else fall through. -/
| jle (i : ℤ) (target : ℕ)
/-- Halt and accept. -/
| accept
/-- Halt and reject. -/
| reject
/-- A BSS program: a finite list of instructions, executed from position `0`. -/
abbrev BSSProgram := List BSSInstr
/-- A machine configuration: program counter and the real-register tape. -/
structure BSSConfig where
/-- The program counter (an index into the program list). -/
pc : ℕ
/-- The bi-infinite tape of real registers. -/
tape : ℤ → ℝ
/-- One execution step. A configuration whose `pc` carries `accept`/`reject`
(or points outside the program) is halted: the step leaves it unchanged. -/
noncomputable def BSSStep (P : BSSProgram) (s : BSSConfig) : BSSConfig :=
match P[s.pc]? with
| none => s
| some ins =>
match ins with
| .const dst c => ⟨s.pc + 1, Function.update s.tape dst c⟩
| .add dst i j => ⟨s.pc + 1, Function.update s.tape dst (s.tape i + s.tape j)⟩
| .sub dst i j => ⟨s.pc + 1, Function.update s.tape dst (s.tape i - s.tape j)⟩
| .mul dst i j => ⟨s.pc + 1, Function.update s.tape dst (s.tape i * s.tape j)⟩
| .div dst i j => ⟨s.pc + 1, Function.update s.tape dst (s.tape i / s.tape j)⟩
| .shiftL => ⟨s.pc + 1, fun k => s.tape (k + 1)⟩
| .shiftR => ⟨s.pc + 1, fun k => s.tape (k - 1)⟩
| .jle i target => if s.tape i ≤ 0 then ⟨target, s.tape⟩ else ⟨s.pc + 1, s.tape⟩
| .accept => s
| .reject => s
/-- The configuration reached after `t` steps of `P` from initial tape `x`
(program counter starting at `0`). -/
noncomputable def BSSRun (P : BSSProgram) (x : ℤ → ℝ) (t : ℕ) : BSSConfig :=
(BSSStep P)^[t] ⟨0, x⟩
/-- The configuration `s` is halted with boolean output `b` — its program
counter carries `accept` (for `b = true`) or `reject` (for `b = false`).
Halted configurations are fixed points of `BSSStep`. -/
def BSSHaltedWith (P : BSSProgram) (s : BSSConfig) (b : Bool) : Prop :=
P[s.pc]? = some (if b then BSSInstr.accept else BSSInstr.reject)
/-- `P`, run on initial tape `x`, halts with output `b` within `T` steps.
`T` is the unit-cost (arithmetic) running time bound. -/
def BSSDecidesInTime (P : BSSProgram) (x : ℤ → ℝ) (T : ℕ) (b : Bool) : Prop :=
∃ t ≤ T, BSSHaltedWith P (BSSRun P x t) b
/-- The `k`th entry of the row-major listing of a matrix (junk value `0` out
of range): `matrixEntryRM A (i*n + j) = A i j`. -/
noncomputable def matrixEntryRM {m n : ℕ} (A : Matrix (Fin m) (Fin n) ℝ)
(k : ℕ) : ℝ :=
if h : k < m * n ∧ 0 < n then
A ⟨k / n, by
have h1 := h.1
rw [Nat.mul_comm] at h1
exact Nat.div_lt_of_lt_mul h1⟩
⟨k % n, Nat.mod_lt _ h.2⟩
else 0
/-- The input tape encoding the LP feasibility instance `∃x, Ax ≥ b`:
cell `0` holds `m`, cell `1` holds `n`, cells `2, …, mn+1` hold `A`
row-major, cells `mn+2, …, mn+m+1` hold `b`, and every other cell is `0`.
The input occupies `mn + m + 2` cells. -/
noncomputable def encodeLP {m n : ℕ} (A : Matrix (Fin m) (Fin n) ℝ)
(b : Fin m → ℝ) : ℤ → ℝ :=
fun k =>
if k = 0 then (m : ℝ)
else if k = 1 then (n : ℝ)
else if 2 ≤ k ∧ k < 2 + (m : ℤ) * n then matrixEntryRM A (k - 2).toNat
else if h : 2 + (m : ℤ) * n ≤ k ∧ k < 2 + (m : ℤ) * n + m then
b ⟨(k - (2 + (m : ℤ) * n)).toNat, by omega⟩
else 0
end SmaleNinth
Read-back
What the Lean code literally says, in plain math · claude-fable-5
Read-back: Def_SmaleNinth_BSSMachine.lean (namespace SmaleNinth)
BSSInstr. An inductive type with exactly ten constructors, each carrying the listed data:
- with and ;
- , , , , each with ;
- and , carrying no data;
- with and ;
- and , carrying no data.
At the level of the type itself these are pure data; the constructors acquire operational meaning only through BSSStep below. Note that the constant in may be any real number, with no restriction (e.g. to rationals or computable reals), and the addresses may be any integers, including negative ones. The jump target of is a natural number and is not required to lie within any program.
BSSProgram. Definitionally, a finite list of BSSInstr values (possibly empty). Instructions are indexed by their position in the list, starting at .
BSSConfig. A structure with two fields: a program counter , and a tape , i.e. an assignment of one real number to every integer address (a bi-infinite tape of real registers). There is no constraint relating to any program, and the tape is an arbitrary function with no finiteness or support condition.
BSSStep. A (noncomputable) total function taking a program and a configuration , where is the tape, and returning a new configuration, by case analysis on the optional lookup of the -th element of the list :
- If (the lookup returns nothing), the result is itself, unchanged.
- If the instruction at position is:
- : the new configuration is , where denotes the function equal to everywhere except at address , where it takes the value ;
- : ; similarly gives , gives , and gives . In all four cases the operands are read from the old tape (so even when or the old values are used), and the division is Lean's total real division, under which for every real ;
- : — every cell takes the old value of its right neighbour;
- : — every cell takes the old value of its left neighbour;
- : if then , otherwise ; the tape is unchanged in both branches;
- or : the result is itself, unchanged.
Thus a configuration whose counter sits on , on , or beyond the end of the program is a fixed point of the step function. A may jump to a position outside the program, after which the configuration is likewise fixed.
BSSRun. For a program , an initial tape , and , is the -fold iterate of applied to the configuration — i.e. the configuration after exactly steps, starting with program counter and tape . For it is itself.
BSSHaltedWith. For a program , a configuration , and a Boolean , the proposition asserting that the lookup of the instruction at position in yields exactly when , and exactly when . In particular a configuration whose counter points outside the program does not satisfy this for either value of , even though it is a fixed point of the step function; and a configuration on any other instruction satisfies it for neither value of .
BSSDecidesInTime. For a program , an initial tape , a time bound , and a Boolean , the proposition
i.e. there exists some number of steps with (the bound is non-strict, and is allowed) such that the configuration reached from after exactly steps has its program counter on (if ) or on (if ). Nothing in this definition asserts uniqueness of or of , and nothing counts instructions in any other way: "time" here is precisely the number of iterations of the step function, each iteration costing one unit regardless of the instruction executed.
matrixEntryRM. For natural numbers (implicit), a real matrix (indexed by ), and , this returns
where and are natural-number division and remainder (the stated side conditions guarantee both indices are in range). So it is the -th entry of the row-major enumeration of , with junk value whenever or (in particular it is identically when or ).
encodeLP. For natural numbers (implicit), a matrix , and a vector (a function on ), this is the tape defined by cases on the address , tested in the following order:
- if : the value is the real number (the natural number cast to );
- else if : the value is the real number ;
- else if and (with cast to ): the value is , where is the truncation of an integer to a natural number (here , so no truncation occurs); by the previous paragraph this equals the row-major entry ;
- else if and : the value is , the index lying in by the range condition;
- otherwise (in particular for every negative and every ): the value is .
Edge cases the definition silently includes: when case 3 is an empty range, and when case 4 is empty, so for or the tape holds only the two header cells (which then contain where the dimension is zero) and is elsewhere. There is no marker distinguishing genuine zero entries of or from the ambient zero padding beyond the dimensions stored in cells and .