LogicQ — verified QEC compilation in Lean 4

A “quantum CompCert”: a Lean 4 verified compiler from chain-complex–typed fault-tolerant programs down to a physical Clifford + measurement target.

Lean Mathlib core proofs license


LogicQ is a Lean 4 workspace for a verified quantum-error-correction (QEC) compilation stack. The code is organized as a tower of small languages, each with its own syntax, semantics, and checker, connected by lowering passes whose soundness theorems are kernel-checked.

A dilution refrigerator, control lines, and an error-corrected qubit chip

Quantum error correction protects a handful of logical qubits by spreading them across many noisy physical qubits on a chip cooled inside a dilution refrigerator (above). Turning a high-level fault-tolerant program into the exact sequence of physical Clifford gates and stabilizer measurements such a machine must run is a long, error-prone compilation. LogicQ makes every stage of that translation a typed, checked artifact — and, for the wired passes, proves that lowering preserves the intended logical action.

The stack

LogicQ compilation pipeline: ChainQ to TypeChecker to Mixed IR to QStab to QClifford, with planned surgery and PPR/PPM passes

The currently wired compiler path is:

ChainQ code families  →  TypeChecker.TypedEnv  →  Compiler LogicalOp  →  Mixed IR

plus the physical extraction edges Mixed / PPM → QStab → QClifford.

The longer target stack — some stages exist today as standalone verified language specs, with the passes between them planned — is:

ChainQ  →  PPR  →  PPM  →  surgery / adapter  →  QStab  →  QClifford

Each box above is a small language with its own syntax, semantics, and checker. Solid arrows are wired edges with soundness theorems; dashed arrows are planned passes or standalone specs.

Honest scope. LogicQ is careful to separate what is proved from what is assumed or planned. Soundness theorems are propext-clean (not advertised as “axiom-free”). Static legality, addressing, and resource discipline are proved; physical channel correctness, code distance, decoders, and fault tolerance are explicit deferred obligations — never silently assumed. The full tier-by-tier contract is in Compiler/CONTRACT.md; the design rationale is in DESIGN.md.

End-to-end LOC by layer

Here LOC means executable IR line count: one QASM instruction, one generated ChainQ/LogicQ primitive, one MixedIR step, one QStab stabilizer instruction, or one final QClifford gate. Declarations, comments, and barriers are excluded. The table splits QStab into the resident-code syndrome pass and the logical-operation fragment, then shows their total. The numbers below are checked in Compiler/QASM/Benchmarks.lean by #guard tests, using the currently wired structural physical path.

The main scaling signal comes from nontrivial code blocks. Bare d=1 rows are only smoke tests: they map one logical qubit to one physical qubit, so equal counts across layers are expected and do not demonstrate physical expansion.

ExampleSetupQASMLogicQMixedIRSyn QStabLogical QStabTotal QStabQCliffordWidth
X; measure Zraw CSS xCheck2222123104
X; measure Zsurface d=22224372810
X; measure Zsurface d=3222124167826
X; measure Zsurface d=42222452915450
X/Z; measure Z/Ztoric d=244486146418
X/Z; measure Z/Ztoric d=34441882613338
X; measure ZHGP [[8,1]]22273104716
X/Z; measure Z/Zlifted product [[15,3]]444126187829
X/Z; measure Z/Ztoy LP [[15,2]]44466125214
X/Z; measure Z/ZBB [[18,4]]44418143218138
cx q[0],q[1]surface d=211185134918
cx q[0],q[1]surface d=311124133715350
cx q[0],q[1]surface d=411148257331398
3-CX chainsurface d=2, 4 blocks33316153110336
3-CX chainsurface d=3, 4 blocks333483987319100
3-CX chainsurface d=4, 4 blocks3339675171651196
cat_state_n4bare d=1 sanity88808884
ghz_n78bare d=1 sanity156156156015615615678

The larger QASMBench rows below are encoded into actual Steane [[7,1,3]] CSS code blocks, one code block per QASM virtual qubit. The compiler checks the Steane code and logical basis, performs logical-qubit allocation, lowers H/CX/X/Z/measurement through the encoded pipeline, prepends one stabilizer-extraction pass for every resident code block, and extracts the resulting QStab program to QClifford. The two positive-suite programs containing T gates (teleportation_n3, qec_en_n5) are checked negatives until magic-state injection is wired into the physical path.

QASMBench sourceEncoded setupQASMLogicQMixedIRSyn QStabLogical QStabTotal QStabQCliffordWidth
qrng_n4Steane x488824325622056
deutsch_n2Steane x277712374913128
iswap_n2Steane x211111112657715928
cat_state_n4Steane x488824325622056
grover_n2Steane x21818181211412620828
lpn_n5Steane x5161616308211231770
hs4_n4Steane x43232322420022438856
bb84_n8Steane x843434348205253645120
qec9xz_n17Steane x176161611023794811106229
cat_state_n22Steane x224444441321763081210308
ghz_state_n23Steane x234646461381843221265322
bv_n14Steane x1454545484300384950195
bv_n19Steane x197474741144105241295265
cat_n35Steane x357070702102804901925490
ghz_n40Steane x408080802403205602200560
bv_n30Steane x301071071071805757551977419
cat_n65Steane x651301301303905209103575910
ghz_n78Steane x78156156156468624109242901092

Additional encoded family sweeps are checked in the same file. These are not hand-counted tables; each row is a #guard that runs the actual QASM/LogicQ/MixedIR/QStab/QClifford pipeline:

FamilyChecked encoded setupPositive pathChecked blockers
raw CSSxCheck2, Steane [[7,1,3]]readout and QASMBench no-magic subsetT/magic QASMBench cases
surfacedistances d = 2,3,4,5readout, one CX, 3-CX chaininvalid d = 0,1; H remains unsupported
toricdistances d = 2,3,4,5two-logical readoutinvalid d = 0,1; naive identity-incidence CX
HGPopen-grid (2,2), (3,2), (3,3), (4,3)encoded readoutmalformed declarations via ChainQ checks
lifted productell = 2,3,4,5 for the line-protograph fixturetwo-logical readoutmalformed declarations via ChainQ checks
BBdemo [[8,2]] plus dimension-jump [[18,2]], [[30,2]], [[54,2]]two-logical readoutzero-logical BB variants reject allocation

Direct MixedIR fixtures are also checked. QASM = 0 and LogicQ = 0 mean the input starts at MixedIR, not that earlier layers compiled away:

ExampleSetupQASMLogicQMixedIRSyn QStabLogical QStabTotal QStabQCliffordWidth
H; S; X; CNOT; two PPMstwo bare blocks00606672
batched CNOT; two Paulis; two PPMstwo bare blocks00505552

The current physical path includes exactly one stabilizer-extraction pass. It does not include repeated syndrome rounds, decoder logic, fault-tolerance padding, or T-gate magic injection; those remain explicit downstream obligations. A naive identity-incidence logical CX on separated toric blocks is also a checked negative today: the compiler cannot prove that incidence realizes the requested logical CNOT for that toric logical basis.

Layers at a glance

FolderLayerWhat lives there
Logicalvocabularylogical block ids and the LQubit address scheme shared by every IR
Physicalvocabularyphysical qubit addresses and the dense 4-letter Pauli alphabet
ChainQL_FE front-endCSS / stabilizer code families, type-checked into proof-carrying CheckedCSSCode
TypeCheckerlegalityaccepts a logical op only when a finite GF(2)/symplectic certificate recomputes
CompilerloweringSource LogicalOp → Mixed IR (compile?) + bridges toward QStab/QClifford
PPRL_PPR speclogical Pauli-product rotations exp(i φ P) with a Mathlib denotation
PPML_PPM specadaptive Pauli-product measurement programs (QMeas)
MagicQmagic statescultivation + Bravyi–Kitaev 15-to-1 distillation protocol checker
QStabL_QStab targetphysical stabilizer-measurement classical dataflow
QCliffordL_QClifford targetphysical Clifford gates + measurement circuits
CodeSwitchingreservedsource-level switching stub (real legality in TypeChecker/Judgment/Switch + Compiler/CodeSwitch)
LatticeSurgeryreservedsurgery-language stub (real surgery IR lives in Compiler/LS)
Libraryreferencesvendored arXiv sources and notes (source-only; gitignored)

Inside the compiler (Compiler/README.md): the Mixed IR target and its lowering; the verified ChainQ2Mixed front-end (path + schedule + QGPU/qLDPC); the QStab2QClifford syndrome-extraction pass; the OpenQASM-2 front-end and the .lqr surface front-end; the lattice-surgery IR; the code-switch certificates; the state-vector Simulator; and the worked Demo programs.

One program at every level — in the project's BNF surface syntax

Every IR level defines its concrete syntax as a BNF grammar in its Syntax.lean, and every level now has a real, total text parser (Parsing/Basic.lean + each layer's Parse.lean), with by decide round-trip tests. Two keyword rules run through the surface syntax — the keywords ARE the AST constructors: every logical instruction carries the Logical keyword, and every Mixed IR instruction leads with its kind keyword (transversal, transversalCNOT, pauli, ppm, magic, switch, …). Below is one minimal program — flip a qubit, then read it out — at each level.

Logical program — every instruction carries the Logical keyword (LogicalOp; parses today — Compiler/Mixed/Parse.lean):

Logical X q[0]                  // logical bit-flip on logical qubit 0
Logical measure q[0]↦Z -> c0    // logical Z-readout into classical bit c0

Mixed IR — each instruction leads with its kind keyword (MixedInstr; parses today — Compiler/Mixed/Parse.lean):

pauli X q[0]                    // the X lowers to a logical Pauli applied to the carrier
ppm c0 := M q[0]↦Z              // the measurement lowers to a native PPM fragment

QASM-compatible front-ends. The same circuit is also accepted as bare-gate text by the .lqr front-end (Compiler/Surface/Parse.lean) and OpenQASM-2 (Compiler/QASM/Parse.lean, ingesting real QASMBench circuits) — these two compile end-to-end to Mixed IR (allocation fills in the Logical/Mixed keywords):

code q as Bare;  X q[0];  measure q[0] -> c[0]      // .lqr
qreg q[1]; creg c[1]; x q[0]; measure q[0] -> c[0]; // OpenQASM 2
-- the .lqr front-end's verified end-to-end claim (Compiler/Surface/Parse.lean):
example : compiles? "code q as Bare\nX q[0]\nmeasure q[0] -> c[0]" = true := by decide

QStab — physical dataflow. BNF: Stmt ::= QVar '=' 'Prop' PauliStr | QVar '=' 'Parity' QVar+:

c0 = Prop Z              // physical Pauli measurement on the bare encoding (Z̄ = Z)

QClifford — physical Clifford + measurement circuit. BNF: Gate ::= 'Prep0' q | 'Prep+' q | ('H'|'S'|'X'|'Z') q | 'CNOT' c t | 'CZ' a b | 'Meas' q '->' CBit | CBit ':=' 'xor' CBit* | 'If' CBit 'then' Pauli q:

X     q0
Prep0 a0                 // fresh |0⟩ ancilla
CNOT  q0 a0
Meas  a0 -> c0           // standard-Z extraction of the Z measurement

The qLDPC encoding. Swap code q as Bare for a ChainQ bivariate-bicycle declaration — code q as BivariateBicycle { l = 3; m = 3; A = x^2*y + x^2*y^2; B = 1 + x*y^2; params = (18,2,3); }, a real parsed macro (Compiler/CodeSwitch/QLDPCPapers/ChainQProgram.lean) — and the logical program is unchanged, but q[0]'s logical becomes the code's high-weight operator, so the physical levels expand. The verified end-to-end LOC table measures this — e.g. X/Z; measure Z/Z on a toy lifted product [[15,2]] is 4 Mixed-IR ops → 12 QStab instructions → 52 QClifford gates over 14 physical qubits, all #guard-checked.

Concrete examples for each layer

Each block shows the program in that layer's BNF grammar (defined in its Syntax.lean). Where a real text parser exists — the .lqr surface front-end and OpenQASM — the text parses and compiles; elsewhere the BNF is the spec and the link points to the machine form: the real, checked Lean AST in source.

1 · Logical & Physical — the shared vocabulary

A logical qubit is Block '[' Nat ']'; the physical target uses a dense Pauli string ('I'|'X'|'Y'|'Z')+:

q[0]            // logical qubit 0 of code block q   (LQubit ::= Block '[' Nat ']')
q3              // a physical qubit (a bare number 3, or tagged q3 — as QStab/QClifford accept)
ZZI             // a dense physical Pauli string on 3 qubits   (PauliStr)

Logical/ · Physical/ · machine form: ⟨0,0⟩, [.Z,.Z,.I]

2 · ChainQ — declare a QEC code family

Code families are declared with the ChainQ code … as … { … } macros (real parsed surface syntax); each elaborates and type-checks (shape, CSS commutation H_X·H_Zᵀ = 0, logical-class membership) into a validity-carrying code:

-- real parsed macros (Compiler/CodeSwitch/QLDPCPapers/ChainQProgram.lean):
code q as BivariateBicycle { l = 3; m = 3; A = x^2*y + x^2*y^2; B = 1 + x*y^2; params = (18, 2, 3); }
code q as LiftedProduct   { ell = 8; rows = 3; cols = 4;
                            protograph = [[x^2,1,1,x^2],[1,x,x^2,x],[x^2,x,x^3,x^2]];
                            params = (200, 20, 10); }
-- surface / toric are CodeDecl kinds built as AST (no `as Surface` macro yet):
--   machine form: CodeDecl.surface 3,  CodeDecl.toric 2

ChainQ/SurfaceSyntax.lean · ChainQ/ · machine form: CodeDecl.bb 3 3 …, CodeDecl.liftedProduct 8 … 3 4

The distinctive judgment is a proof-carrying capability matcher, over the PPM measurement BNF (the PPM measurement statement r ':=' 'M' MTarget): a cross-code joint measurement Z̄ ⊗ Z̄ is rejected unless an installed adapter capability recomputes a valid merged-code certificate:

c0 := M q[0]↦Z                  // OK: native single-block measurement
c0 := M q[0]↦Z, r[0]↦Z          // REJECTED: cross-code joint Z̄⊗Z̄ with no capability
                                //  …admitted once an adapter capability is installed

TypeChecker/Judgment/PPM/Examples.lean · TypeChecker/ · machine form: the MTarget + Capability record

4 · Compiler / Mixed IR — the logical source and its keyword-led lowering

A Logical-prefixed source program lowers to the Mixed IR, where each instruction leads with its kind keyword. Logical H; Logical S becomes two direct transversals (and execMixed-runs to the same state as the ideal simulator — exact-operational equality). Both languages parse today (Compiler/Mixed/Parse.lean):

// Logical source — every instruction carries the `Logical` keyword:
Logical H q[0]
Logical S q[0]
// → lowers to Mixed IR — every instruction leads with its kind keyword:
transversal 0 H            // MixedInstr.transversal 0 hGate2x2
transversal 0 S            // MixedInstr.transversal 0 sGate2x2

The complete Mixed IR instruction set — all eight keywords. Each colored pill below is a MixedInstr constructor; every instruction in the IR leads with one of them:

ppm transversal transversalCNOT transversalCNOTBatch automorphism switch magic pauli

// ── these five parse today (Compiler/Mixed/Parse.lean) ──
ppm c0 := M q[0]↦Z                  // ppm          — a native PPM/PPU fragment
transversal 0 H                     // transversal  — a local single-qubit transversal Clifford
transversalCNOT q[0] q[1] [[1]]     // transversalCNOT — inter-block incidence-checked logical CNOT
pauli X q[0]                        // pauli        — a logical Pauli applied to the carrier
magic T q[0]                        // magic        — a deferred, typed magic-state (T) obligation
// ── these three are keyword-led; their matrix / Block / cert payload stays machine-form ──
automorphism 0 [[ ..2n×2n symplectic.. ]]               // automorphism — an arbitrary symplectic logical automorphism
switch 0 repCode3 { kind := .gaugeFix, f := encF }      // switch       — a code switch (consumes/transforms block 0)
transversalCNOTBatch 0 1 [[1]] [[1]]                    // transversalCNOTBatch — a batched high-rate logical CNOT

Compiler/Mixed/Parse.lean · Compiler/Demo/Contract.lean · Compiler/Mixed/ · machine form: [.ppm …, .transversal …, .transversalCNOT …, .pauli …, .magic …, .automorphism …, .switch …, .transversalCNOTBatch …]

5 · ChainQ2Mixed — request ≠ realization (transversal CNOT)

The front-end separates what a logical op requests from how it is realized. A logical CNOT lowers to the Mixed IR transversalCNOT keyword, which carries the physical incidence matrix; a non-trivial incidence realizes a verified transversal CNOT, while a zero incidence that still claims a logical CNOT is rejected (the lifted symplectic map would induce the identity, not the CNOT):

Logical CNOT q[0] r[0]                     // logical source
transversalCNOT q[0] r[0] [[1]]            // OK: realized as a transversal logical CNOT
transversalCNOT q[0] r[0] [[0]]            // REJECTED: zero incidence ≠ a logical CNOT

Compiler/Mixed/Parse.lean · Compiler/ChainQ2Mixed/Primitive.lean · Compiler/ChainQ2Mixed/ · machine form: .transversalCNOT {control, target, incidence}

6 · PPR — logical Pauli-product rotations

The L_PPR spec. BNF: Rot ::= ('+'|'-') Angle '·' PauliString, Angle ::= 'π'|'π/2'|'π/4'|'π/8', PauliString ::= (LQubit '↦' Pauli)*. The π/8 count is the T-count — this program has T-count 2:

+π/8 · q[0]↦Z              // a T rotation
+π/4 · q[0]↦Z              // an S rotation
+π/8 · q[0]↦Z q[1]↦Z       // a two-qubit ZZ rotation

PPR/Syntax.lean · parses today: PPR/Parse.lean · PPR/ · machine form: ⟨⟨false, .piEighth⟩, [(⟨0,0⟩, .Z)]⟩

7 · PPM — adaptive Pauli-product measurement (QMeas)

The L_PPM measurement language. BNF (the measurement statement — the full Stmt also has frame/discard/if/for/skip/abort): S ::= r ':=' 'M' MTarget, MTarget ::= (LQubit '↦' PLetter)* — a one- or two-body logical observable (the natively lattice-surgery-realizable alphabet). a is an ancilla code block:

c0 := M q[0]↦Z, a[0]↦X     // OK: a two-body joint observable
c1 := M q[0]↦X             // OK: a one-body observable
c2 := M q[0]↦Z, q[0]↦X     // REJECTED: a repeated qubit

PPM/Syntax.lean · parses today: PPM/Parse.lean · PPM/ · machine form: [(dataQ 0,.Z),(ancQ 0,.X)]

8 · Code switching — a transparent cross-code coercion

Code switching has no surface grammar — it is a checked certificate (a kind + a symplectic map f). Encoding a bare qubit into the [[3,1,1]] repetition code preserves the logical operators (it induces X̄ = XXX, Z̄ = Z₀); a degenerate all-zero map is rejected:

-- machine form: the SwitchProtocolCert value
{ kind := .gaugeFix, f := [[true,true,true,false,false,false],   -- X̄ ↦ XXX
                           [false,false,false,true,false,false]] }  -- Z̄ ↦ Z₀   (OK)
{ kind := .gaugeFix, f := zeroMat 2 6 }                            -- REJECTED: zero map

TypeChecker/Judgment/Switch/Examples.lean · Compiler/CodeSwitch/ · machine form: {kind := .gaugeFix, f := [[…]]}

9 · MagicQ — magic-state protocols

A magic-state protocol is a list of ProtocolOps (rendered top-to-bottom below; each line leads with its op keyword — the discriminating constructor). The colored pills are the protocol-op keyword set:

inject assumeLogicalCheck grow stabilize graft transitionToMatchable postselect measureSyndrome output

(assumeLogicalCheck is an assumption marker — it records a check the type system can't yet prove, e.g. the non-Pauli H_XY, as an explicit deferred obligation — not a computational primitive.)

Magic-state cultivation (Gidney–Shutty–Jones, 2409.17595) — a live-carrier protocol that grows one cheap T state through inject → check → grow → stabilize → escape, threading a single carrier 0. The non-Pauli H_XY double-check, the growth fault distance, and the escape decoder gap stay explicit deferred obligations, never claimed proven:

-- the cultivate_T Protocol value (MagicQ/Library/Cultivation.lean), default spec d1=5, d2=15:
inject                 T -> carrier 0  in ColorCode(3)                 -- unitary injection of encoded |T⟩
assumeLogicalCheck     carrier 0  H_XY  @ "double-check"               -- non-Pauli (X+Y)/√2 T-check (DEFERRED)
postselect             all-detectors                                  -- early-stage FULL postselection
grow                   carrier 0 -> ColorCode(d1=5)   faultDistance 5 @ "grow.bell-boundary"
stabilize              carrier 0  superdense × 3       @ "stabilize.superdense"
graft                  carrier 0 -> Grafted(d2=15)    codeDistance 15 @ "escape.graft"
stabilize              carrier 0  rounds 5             @ "escape.idle-grafted"     -- r1 grafted-code rounds
transitionToMatchable  carrier 0 -> Matchable(d2=15)  codeDistance 15 @ "escape.transition"
stabilize              carrier 0  rounds 5             @ "escape.idle-matchable"   -- r2 matchable rounds
postselect             detectors @ "escape.transition"
postselect             decoderGap "gap ≥ Δ"                            -- kept iff decoder gap ≥ threshold (DEFERRED)
output                 resource 0                                      -- cultivated |T⟩: faultDistance ≥ 5, codeDistance 15

MagicQ/Library/Cultivation.lean · MagicQ/ · machine form: the cultivateT / defaultT Protocol value

Standard 15-to-1 distillation (15 T inputs → one output) — now a library composition of primitives, not a single op. 15-to-1 is inject ×15 → measureSyndrome → postselect → output, where measureSyndrome is the generic syndrome-measure primitive (the "exactly 15" is a property of this protocol, not of the primitive). The non-Pauli Bravyi–Kitaev A-type η-syndrome decoding stays a deferred obligation:

-- the rm15_to_1 Protocol value (MagicQ/Library/ReedMuller15.lean):
inject          t[0..14] : T          -- 15 supplied noisy T inputs (15× inject)
measureSyndrome t[0..14] -> t : RM15  -- generic primitive: measure the RM-15 η syndrome, project out the T
postselect      η == 0                -- keep iff the A-type syndrome η = 0   (η decoding deferred)
output          t

MagicQ/Tests.lean · MagicQ/ · machine form: the rm15_to_1 Protocol value

10 · QStab — physical stabilizer-measurement dataflow

The L_QStab target. BNF: Stmt ::= QVar '=' 'Prop' Sched? PauliStr | QVar '=' 'Parity' QVar+ — an SSA-style dataflow of physical Pauli measurements and classical parities (syndrome detectors plus a logical readout):

c0 = Prop ZZI            -- physical stabilizer measurement
c1 = Prop IZZ
c2 = Prop ZZI
d0 = Parity c0 c2        -- syndrome detector
c3 = Prop IZZ
d1 = Parity c1 c3        -- syndrome detector
c4 = Prop ZZZ            -- logical Z
o0 = Parity c4           -- logical output

QStab/Syntax.lean · parses today: QStab/Parse.lean · QStab/ · machine form: [.prop …, .parity …]

11 · QClifford — the physical Clifford + measurement target

The terminal L_QClifford IR. BNF: Gate ::= 'Prep0' q | 'Prep+' q | ('H'|'S'|'X'|'Z') q | 'CNOT' c t | 'CZ' a b | 'Meas' q '->' CBit | CBit ':=' 'xor' CBit* | 'If' CBit 'then' Pauli q. E.g. CNOT(0,1) realized from a CZ:

H    q1                  -- CNOT q0, q1  =  H · CZ · H
CZ   q0 q1
H    q1

QClifford/Syntax.lean · parses today: QClifford/Parse.lean · QClifford/ · machine form: [.H 1, .CZ 0 1, .H 1]

12 · QStab → QClifford — the syndrome-extraction pass

Each physical stabilizer measurement is extracted by a chosen scheme (standard / destructive / Shor / Knill / flag). A standard-Z measurement of ZZ on data qubits {0,1} extracts to this QClifford circuit:

Prep0 q3                 -- fresh |0⟩ ancilla, physical qubit 3
CNOT  q1 q3
CNOT  q0 q3
Meas  q3 -> c7           -- one measurement into result var 7

Compiler/QStab2QClifford/Basic.lean · Compiler/QStab2QClifford/ · machine form: [.prepZero 3, .CNOT 1 3, .CNOT 0 3, .meas 3 7]

Public imports

The repository root intentionally has no .lean files. Import public layers through their folder-owned entrypoints:

import LogicQ.Basic        -- umbrella over the whole workspace
import ChainQ.Basic        -- front-end code type system
import TypeChecker.Basic   -- legality checker + soundness
import Compiler.Basic      -- Source LogicalOp → Mixed IR (the wired compiler)
import PPR.Basic           -- Pauli-product rotations (spec)
import PPM.Basic           -- adaptive Pauli-product measurement (spec)
import MagicQ.Basic        -- magic-state protocol checker
import QStab.Basic         -- physical stabilizer dataflow (spec)
import QClifford.Basic     -- physical Clifford target (spec)

Each source folder has its own README with the local syntax, semantic rule, and small examples.

Build

lake build
lake build LogicQ.Basic ChainQ.Basic TypeChecker.Basic Compiler.Basic

The project uses Lean v4.29.1 and Mathlib v4.29.1. Most of the stack is Mathlib-free (the front-end type system, PPM, QStab, and QClifford are pure Bool/List/Nat); Mathlib enters only for the analytic PPR denotation (the complex-matrix meaning of exp(i φ P)).

License

MIT © 2026 John ye.