Pick one of three sample Qiskit programs. The page reimplements the LintQ extractor + three analyses (OpAfterMeas, DoubleMeas, GhostCompose) in the browser and lints the code live — no server, no Qiskit install. Results are verified against the real Soufflé 2.5 pipeline as ground truth.
# click "Run LintQ"
LintQ turns your Qiskit source into a set of facts (rows in tables), then applies Datalog rules to those facts to produce warnings. There are three layers. You do not need to read a specific example to read facts — every fact has the same shape and meaning regardless of the circuit.
.facts files)These are extracted directly from the source by
extractor/ast_to_facts.py, one relation per quantum/AST
abstraction. The demo shows them in the “Extracted facts (EDB)”
box: Stmt, CFGEdge, Assign,
CircuitAlloc, GateOp, MeasureOp,
CircuitCall. Each row is tab-separated; the first
column is almost always a statement id (the extractor numbers
statements in source order — the module docstring is statement 1).
Use the Stmt table to map a statement id back to its source line.
The engine computes extra relations on top of the EDB before it can decide
whether a warning fires. These are the “derived facts”: they are
not written to disk by the extractor, but the rules in
engine/lintq.dl build them and the final warning rules read
them. The most important ones:
AssignedStmt(stmt) — every stmt that is
also an assignment. A compose() whose stmt is
not in this set is discarded → GhostCompose.ModifiedQubit(circuit, qubit, stmt) — stmt
applies a gate to qubit. This breaks a DoubleMeas path: if a
modification sits between two measurements, they are not redundant.ReachableAfterMeasure(circuit, qubit, stmt) — all
statements reachable along the control-flow graph from a measurement of
qubit. If one of them is a GateOp on the same
qubit, you get an OpAfterMeas warning.MeasReachesMeas(circuit, qubit, first, cur) —
cur is reachable from measurement first without
any qubit-modifying gate in between. When cur is itself a
measurement of the same qubit, the engine emits DoubleMeas.Tick “Show derived facts” above to see exactly which of these rows your current program produces. A warning is simply the engine's conclusion that one of these derived relations crosses a threshold (e.g. a reachable gate after a measure).
Warn*.csv files)These are what the linter reports. Each warning row records the
statement ids involved; look them up in Stmt to find the
source lines. The columns are:
WarnOpAfterMeas(gate_stmt, circuit, gate, qubit, meas_stmt)WarnDoubleMeas(second_meas, circuit, qubit, first_meas)WarnGhostCompose(stmt, circuit, subcircuit)The live demo renders these as plain sentences with line numbers (see the Warnings box). The MCP server does the same and then shuffles the sentence list so an agent is not biased by detection order — the shuffle only reorders the readable strings; it does not change which warnings exist.
demo.js) is a faithful port of
extractor/ast_to_facts.py + engine/lintq.dl, covered by
demo.test.js against the real Soufflé 2.5 outputs (ground truth:
3, 2, 0 warnings on the three samples — all reproduced exactly).