The ambient cost model #
This file fixes the cost model in which every polynomial-time statement of the
project is made: the transformations of the compression pipeline (introspection,
oracularization, answer reduction, parallel repetition), the Compress map, the
efficient computability toolkit (universal machine, s-m-n, Kleene fixed point;
blueprint Section sec:rr-computability), and the recursive compression lemma
(blueprint lem:recursive-compression, [MNY] Lemma 5.1).
The model #
Data are binary trees (Data: nil and cons), the S-expressions in which bit
strings, numbers, pairs and programs are all encoded (Cost.Encoding). Data.size
counts nodes; it is the bit-length of the preorder serialization Data.toBits, so
sizes are additive under pairing (R4 below).
Programs (Prog) form a minimal first-order language with de Bruijn variables over an
environment of Data values: var i reads a variable, nil, const d and cons h t
build values, elim i n c inspects the i-th variable (binding the two components of
a cons), let_ e b binds, and loop b iterates b on the state held in variable 0
until it signals stop. The timed big-step semantics Eval env p r t charges one unit
per rule, except that reading a variable or a literal costs the size of the value:
values are copied when read and inspected in place by elim. Consequently a run
of cost t produces a result of size at most t (Eval.size_le), so every value
occurring in a computation is polynomially bounded by the running time โ which is what
makes the unit costs honest under a pointer-machine, and then Turing-machine, simulation
with polynomial overhead (meta-remark below).
Why this model (decision record) #
The choice is driven by the requirements extracted from the JNVWY pipeline:
- R1 (programmability): deciders perform real algorithms (linear algebra over
๐ฝโ/๐ฝ_{2^k}, low-degree evaluations, simulations); their polynomial time bounds must be provable via a compositional closure library. - R2 (self-reference): efficient universal machine, s-m-n, and Kleene fixed point, with explicit polynomial overheads (the recursion in [MNY, Lemma 5.1] and the ฮป-boundedness bookkeeping of [JNVWY, ยง12] need them).
- R3 (arithmetizable tableaux): answer reduction needs bounded computations of
this model to have succinct, formula-uniform 3SAT tableaux (blueprint
thm:succinct-sat). This is discharged through a single gateway theorem whose proof compiles the model to the machine model ofMIPRE/TM(planned Milestone H1 ofplanning/tm-infrastructure.md). The low-level machine appears in no statement outside that proof. - R4 (binary-length sizes): indices
nenter in binary; "succinct" meanspoly(log)of the described object.
Three natural alternatives fail:
Nat.Partrec.Code(with any cost semantics) is not a viable carrier of polynomial time: its primitives reach large values only throughsucc-chains, value-indexedprecrecursion, orrfindsearch, so evenn โฆ 2non binary representations has nopolylog(n)-cost program โ the induced "P" would not contain binary addition. Its numeric pairing (Nat.pair, quadratic) also distorts lengths exponentially under nesting. It remains the model of the final computability statements (MIPRE.HaltingGameValue), reached via a one-time compilation (Foundations/Compression.lean).- Mathlib's
Turing.ToPartrec.Code, the model used until 2026-09-08, cannot rebuild lists in polynomial time. Its primitives act only on the front of a singleList โvalue (prepend, drop or replace the first cell), and the value is passed by value; so every output has the formp ++ v.drop k, and the input suffix can only be discarded by first dropping everything built in front of it, which retains a program-size-bounded number of cells of polynomially bounded value โO(log t)bits of information. HenceList.reverse,x โฆ x ++ [b], binary addition and the runtime s-m-n map are not polynomial-time computable there: it is a one-stack machine with a read-only input, adequate for Mathlib's numeric use (Code.exists_codereturns singletons[n]) but not for string processing. (Trailing0cells are moreover invisible to every program.) - Turing machines (
Turing.TM2,Turing.FinTM2, the project's ownTuring.Code i) satisfy R3 natively but fail R1/R2 in practice: Mathlib has no universal machine, no composition, and no way to program nontrivial algorithms; machine-level combinator libraries (CSLib's, under construction) cost hundreds of lines per combinator.
Prog sits in the sweet spot: cons builds and elim destructs anywhere in a value, so
string algorithms and recursion on notation are direct (R1); programs are trees, hence
data with additive sizes (Prog.toData in Cost.Encoding), and hardcoding an argument is
let_ (cons (const d) (var 0)) at linear cost (R2, R4); and the language is small enough
for its metatheory and for a self-interpreter โ the universal machine of Cost.Toolkit โ
to be manageable, and to be compiled to the machine model for R3. The design follows the
"rose tree machine" idea of C. Reitwiessner (CSLib issue #611) with binary trees in place of
rose trees and a time-only semantics.
Meta-remark (not formalized). A pointer machine represents values as DAGs of cons
cells: cons, elim and let_ are constant-time, var i and const d copy a value in
time proportional to its size (exactly the charged cost), so a run of cost t takes O(t)
pointer-machine time on O(t + input) cells, and Turing-machine time polynomial in that.
This justifies reading PolyTimeFun as honest "polynomial time"; nothing in the project
depends on it formally, since the final theorem only claims Computable.
Main definitions #
MIPRE.Cost.Data,Data.size,Data.toBits,Data.ofNat(unary numerals).MIPRE.Cost.Prog,Prog.WellScoped.MIPRE.Cost.Env,Env.get.MIPRE.Cost.Eval: the timed big-step semantics;Eval.deterministic,Eval.pos,Eval.size_le, and the scoping lemmasEval.append_of_wellScoped/Eval.of_append_of_wellScoped(extra environment entries are inert for well-scoped programs).MIPRE.Cost.evalFuel: an executable evaluator with fuel, sound forEval.MIPRE.Cost.Halts,HaltsWithin,TimeBound.
Blueprint: this file is part of sec:rr-computability (efficient computability
toolkit), infrastructure level.
Equations
- One or more equations did not get rendered due to their size.
- MIPRE.Cost.instDecidableEqData.decEq MIPRE.Cost.Data.nil MIPRE.Cost.Data.nil = isTrue โฏ
- MIPRE.Cost.instDecidableEqData.decEq MIPRE.Cost.Data.nil (a.cons a_1) = isFalse โฏ
- MIPRE.Cost.instDecidableEqData.decEq (a.cons a_1) MIPRE.Cost.Data.nil = isFalse โฏ
Instances For
Equations
- MIPRE.Cost.instReprData = { reprPrec := MIPRE.Cost.instReprData.repr }
Equations
- One or more equations did not get rendered due to their size.
- MIPRE.Cost.instReprData.repr MIPRE.Cost.Data.nil precโ = Repr.addAppParen (Std.Format.nest (if precโ โฅ 1024 then 1 else 2) (Std.Format.text "MIPRE.Cost.Data.nil")).group precโ
Instances For
Equations
Programs of the ambient model, with de Bruijn variables (var 0 is the innermost
bound variable; the input of a program is var 0).
- var
(i : โ)
: Prog
Read variable
i(copying it: cost1 + size). - nil : Prog
The atom.
- const
(d : Data)
: Prog
Literal data: evaluates to
d, at costd.size(the value is built). - cons
(h t : Prog)
: Prog
Build a node from the values of
handt. - elim (i : โ) (n c : Prog) : Prog
- let_
(e b : Prog)
: Prog
Bind the value of
eas variable0and runb. - loop (b : Prog) : Prog
Instances For
Equations
- One or more equations did not get rendered due to their size.
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var a) (MIPRE.Cost.Prog.var b) = if h : a = b then h โธ isTrue โฏ else isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) (MIPRE.Cost.Prog.elim i_1 n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) (e.let_ b) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.var i) b.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil (MIPRE.Cost.Prog.var i) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil MIPRE.Cost.Prog.nil = isTrue โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil (MIPRE.Cost.Prog.elim i n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil (e.let_ b) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq MIPRE.Cost.Prog.nil b.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) (MIPRE.Cost.Prog.var i) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const a) (MIPRE.Cost.Prog.const b) = if h : a = b then h โธ isTrue โฏ else isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) (MIPRE.Cost.Prog.elim i n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) (e.let_ b) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.const d) b.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) (MIPRE.Cost.Prog.var i) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) (MIPRE.Cost.Prog.elim i n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) (e.let_ b) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (h.cons t) b.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) (MIPRE.Cost.Prog.var i_1) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) (e.let_ b) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (MIPRE.Cost.Prog.elim i n c) b.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) (MIPRE.Cost.Prog.var i) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) (MIPRE.Cost.Prog.elim i n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq (e.let_ b) b_1.loop = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop (MIPRE.Cost.Prog.var i) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop MIPRE.Cost.Prog.nil = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop (MIPRE.Cost.Prog.const d) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop (h.cons t) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop (MIPRE.Cost.Prog.elim i n c) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq b.loop (e.let_ b_1) = isFalse โฏ
- MIPRE.Cost.instDecidableEqProg.decEq a.loop b.loop = if h : a = b then h โธ have inst := MIPRE.Cost.instDecidableEqProg.decEq a a; isTrue โฏ else isFalse โฏ
Instances For
Equations
- MIPRE.Cost.instReprProg = { reprPrec := MIPRE.Cost.instReprProg.repr }
Equations
- One or more equations did not get rendered due to their size.
- MIPRE.Cost.instReprProg.repr MIPRE.Cost.Prog.nil precโ = Repr.addAppParen (Std.Format.nest (if precโ โฅ 1024 then 1 else 2) (Std.Format.text "MIPRE.Cost.Prog.nil")).group precโ
Instances For
Equations
WellScoped n p: every variable of p is bound in an environment of length n.
Equations
- MIPRE.Cost.Prog.WellScoped xโ (MIPRE.Cost.Prog.var i) = (i < xโ)
- MIPRE.Cost.Prog.WellScoped xโ MIPRE.Cost.Prog.nil = True
- MIPRE.Cost.Prog.WellScoped xโ (MIPRE.Cost.Prog.const d) = True
- MIPRE.Cost.Prog.WellScoped xโ (h.cons t) = (MIPRE.Cost.Prog.WellScoped xโ h โง MIPRE.Cost.Prog.WellScoped xโ t)
- MIPRE.Cost.Prog.WellScoped xโ (MIPRE.Cost.Prog.elim i a c) = (i < xโ โง MIPRE.Cost.Prog.WellScoped xโ a โง MIPRE.Cost.Prog.WellScoped (xโ + 2) c)
- MIPRE.Cost.Prog.WellScoped xโ (e.let_ b) = (MIPRE.Cost.Prog.WellScoped xโ e โง MIPRE.Cost.Prog.WellScoped (xโ + 1) b)
- MIPRE.Cost.Prog.WellScoped xโ b.loop = (0 < xโ โง MIPRE.Cost.Prog.WellScoped xโ b)
Instances For
Environments: the values of the variables, innermost (index 0) first.
Equations
Instances For
Variable lookup; reading beyond the environment gives nil, so that the semantics is
total.
Equations
- env.get i = List.getD env i MIPRE.Cost.Data.nil
Instances For
Timed big-step semantics: Eval env p r t means that p, in environment env, halts
with result r at cost t. One unit per rule; reading a variable or a literal additionally
costs the size of the value.
- var (env : Env) (i : โ) : Eval env (Prog.var i) (env.get i) ((env.get i).size + 1)
- nil (env : Env) : Eval env Prog.nil Data.nil 1
- const (env : Env) (d : Data) : Eval env (Prog.const d) d d.size
- cons {env : Env} {h t : Prog} {a b : Data} {s u : โ} : Eval env h a s โ Eval env t b u โ Eval env (h.cons t) (a.cons b) (s + u + 1)
- elim_nil {env : Env} {i : โ} {n c : Prog} {r : Data} {t : โ} : env.get i = Data.nil โ Eval env n r t โ Eval env (Prog.elim i n c) r (t + 1)
- elim_cons {env : Env} {i : โ} {n c : Prog} {a b r : Data} {t : โ} : env.get i = a.cons b โ Eval (a :: b :: env) c r t โ Eval env (Prog.elim i n c) r (t + 1)
- let_ {env : Env} {e b : Prog} {v r : Data} {s t : โ} : Eval env e v s โ Eval (v :: env) b r t โ Eval env (e.let_ b) r (s + t + 1)
- loop_nil {env : Env} {b : Prog} {t : โ} : Eval env b Data.nil t โ Eval env b.loop Data.nil (t + 1)
- loop_stop {env : Env} {b : Prog} {r : Data} {t : โ} : Eval env b (Data.nil.cons r) t โ Eval env b.loop r (t + 1)
- loop_step {env : Env} {b : Prog} {x y v r : Data} {s t : โ} : Eval env b ((x.cons y).cons v) s โ Eval (v :: List.tail env) b.loop r t โ Eval env b.loop r (s + t + 1)
Instances For
Extra environment entries are inert for a well-scoped program (weakening).
Extra environment entries are inert for a well-scoped program (strengthening).
Executable evaluator with fuel (one unit of fuel per rule), returning the result and its cost.
Equations
- One or more equations did not get rendered due to their size.
- MIPRE.Cost.evalFuel 0 xโยน xโ = none
- MIPRE.Cost.evalFuel n.succ xโ (MIPRE.Cost.Prog.var i) = some (xโ.get i, (xโ.get i).size + 1)
- MIPRE.Cost.evalFuel n.succ xโ MIPRE.Cost.Prog.nil = some (MIPRE.Cost.Data.nil, 1)
- MIPRE.Cost.evalFuel n.succ xโ (MIPRE.Cost.Prog.const d) = some (d, d.size)
- MIPRE.Cost.evalFuel f.succ xโ (h.cons t) = match MIPRE.Cost.evalFuel f xโ h, MIPRE.Cost.evalFuel f xโ t with | some (a, s), some (b, u) => some (a.cons b, s + u + 1) | x, x_1 => none
Instances For
A (total) time bound for p as a function of the input size. This is the notion
TIME_๐ฎ, TIME_๐ โค โฏ of blueprint def:lambda-bounded specializes.
Equations
- MIPRE.Cost.TimeBound p T = โ (x : MIPRE.Cost.Data), MIPRE.Cost.HaltsWithin p x (T x.size)