The Lean model¶
The Lean package defines formal semantics for a fragment of serQ and proves properties of programs in that fragment. The Rust interpreter and Lean semantics are tested for agreement; their equivalence is not proved. A release tag identifies both implementations.
What you can verify¶
| Result | Scope | Example |
|---|---|---|
| A scenario's outcome | One program and an explicit workload | Generated oracle theorems in lean/Serq/Oracle.lean |
| A program claim | All paths in the claim's workload family satisfying its assumptions | Claims and proofs for the paper examples |
| A stochastic result | A separately defined arrival law and the theorem's assumptions | Stability and recurrence results in the Dai and Bari examples |
Claims¶
Write a claim in a program to state a property of its
paths. The simulator checks the path it runs. A Lean proof establishes the
corresponding statement over the workloads and paths admitted by that
statement.
For examples/papers/*.sq:
make claims-ircompiles the programs intotools/claims/*.ir.jsonand generates statements inlean/Serq/Claims.lean.- Proofs live beside the programs in
examples/papers/*.lean. - The generated
ClaimsProved.leanrequires a proof for each claim.
The generated workload families allow up to 500 sessions. Drawn attributes
range over natural numbers, subject to given; this is not a probability
law. Results about random arrivals need the separate stochastic models
described in the Dai, Bari and
Kong examples.
Build and check¶
The package is in lean/ and uses Mathlib v4.34.0. Download its cache for
the first build, then run the repository check:
make lean checks generated statements, builds the semantics and paper
proofs, rejects sorry, and audits the declarations listed in
lean/scripts/AxiomAudit.lean. The permitted axioms are propext,
Classical.choice and Quot.sound.
To check one paper proof after building its dependencies:
Use from another Lean project¶
Add a pinned dependency to your Lake configuration:
[[require]]
name = "Serq"
git = "https://github.com/servingQ/serQ"
rev = "<tag or commit>"
subDir = "lean"
Import Serq or a specific module. Definitions use the namespace SerqLang.
The library Serq contains the semantics; papers contains proofs from
examples/papers/.
Compare with the interpreter¶
After make lean and cargo build --release, run:
This compares every session's observations between the Rust interpreter and
the Lean executable for 200 fixed random cases and the full replay trace.
Random cases vary the engine configuration, iteration costs and explicit
sessions. A failing case is saved under target/lean-drt/<seed>/.
The random cases exercise the vLLM replay program, not arbitrary serQ
programs. Targeted regressions in tests/lean-regress/ and
lean/Serq/Regress.lean cover additional cases. Passing these comparisons
is evidence of agreement on the tested paths, not a proof of equivalence.
For an individual replay comparison, use scripts/lean_bench.py with
small, full, cost or fullcost. The cost modes compare observations
using integer microsecond or nanosecond clocks.
What is not covered yet¶
The generators accept a fragment of the IR, not the full language. See the IR reference for the translation boundary. Unsupported constructs are rejected rather than silently omitted.
- Values and time use natural numbers. Iteration costs have a constant
term of at least one and supported terms in
tokens,prefilled,decoders,kv_decodeandattention. Attention is represented by twice its value, so its IR coefficient must be even. Fractional coefficients and costs readingresidents,kv_prefillornoware rejected. - A
whileguard must be a literal 0/1, a comparison or logical expression, a conditional with such results, or the read-onlymoreattribute of an explicit-session workload whose presets formoreare all 0/1. Assignments tomoreand other bare attribute guards are rejected. A guard and every assignment feeding its attributes must be free of subtraction: natural subtraction can change a comparison even when its result is 0/1. This conservative restriction includes differences that happen to stay nonnegative. Every division in the guard or those assignments must have a divisor that folds to a positive natural constant. Dynamic divisors are rejected, including ones that happen to stay positive; Lean division by zero yields zero where Rust produces infinity or NaN. Rust reports invalid guards at runtime; Lean's executable model has no corresponding error state. - The claims fragment also supports the body an engine's shared
only (p)lowers to, a chunk expression overresidentsandqueued(p), one queue key on a pool that no run grows, and cost terms of the formk * ceil(tokens / b). A claim read at the end aggregates withtotal,countorprefix_total;largestandsmallestare rejected. - Renewal arrivals, transfers between pools and flows over several stages are outside the executable fragment. Stochastic paper results use separate constructions, rather than translating arbitrary stochastic workloads.
Find a definition or proof¶
| Topic | Source |
|---|---|
| Pool semantics | lean/Serq/Core.lean |
| Executable semantics | lean/Serq/Exec.lean |
| Claims and reachable states | lean/Serq/Claim.lean, lean/Serq/Inv.lean |
| Serving order and work conservation | lean/Serq/Serve.lean, lean/Serq/Fill.lean, lean/Serq/Work.lean |
| Random arrivals, drift and recurrence | lean/Serq/Chain.lean, lean/Serq/Poisson.lean, lean/Serq/Foster.lean, lean/Serq/Recurrence.lean |
| Generated scenarios and claims | lean/Serq/Oracle.lean, lean/Serq/Claims.lean |
| Program-specific proofs | examples/papers/*.lean |