Compilation Pipeline¶
Compilation turns a block graph into a physical program. Bloq plans which logical relations each measurement and output correction needs, builds the fault-tolerant physical circuits for every block, and binds the two together with the classical logic that runs between them. The result is Bloq IR. Backend emission is a separate step.
This chapter walks through each compilation stage. The logical planning stage is explained in Correlation Surfaces, and the physical circuits in Circuit Constructions.
Compile a graph¶
The same entry point accepts a local BlockGraph or a graph containing module
definitions and placed instances. Here we compile a gallery CNOT at distance 3:
import bloq
graph = bloq.GalleryItem.CNOT.load()
program = bloq.compile(graph, distance=3)
program.save("cnot.bloqir")
use bloq::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let graph = GalleryItem::CNOT.build();
let program = compile(&graph, 3)?;
std::fs::write("cnot.bloqir", program.to_text())?;
Ok(())
}
bloq compile --gallery cnot -d 3 --backend ir-text -o cnot.bloqir
Stages at a glance¶
flowchart LR src["Block graph"] --> val["1 Validation"] val --> cert["2 Certification"] cert --> corr["3 Correlations"] corr --> place["4 Placement"] place --> tmpl["5 Templates"] tmpl --> read["6 Readouts"] read --> fin["7 Finalization"] fin --> ir["Bloq IR"]
Stage |
Operation |
Question it answers |
Result |
|---|---|---|---|
1. Validation |
Validating source |
Is the source well formed and within size limits? |
Checked source |
2. Certification |
Certifying module |
Do module definitions keep their interface contracts? |
Linked definitions, or a cached artifact |
3. Correlations |
Planning correlations |
Which logical relations recover each value and output frame? |
Readout plan |
4. Placement |
Placing physical blocks |
Which extraction schedule does each patch use, and where? |
Scheduled physical cases |
5. Templates |
Binding physical program |
Which circuits realize the blocks, and which checks join them? |
Placed instances and detectors |
6. Readouts |
Lowering readouts |
Which physical records realize each planned relation? |
Observables and classical program |
7. Finalization |
Finalizing program |
How do the pieces form one ordered, checked program? |
Optimized Bloq IR |
Stages 1 to 3 read only the block graph and do not depend on code distance. Stages 4 to 7 build physical circuits whose size grows with distance.
1. Validation¶
Bloq first checks that the source describes a valid computation:
Pipes join compatible faces, and Ports, T resources, and caps have their required connections.
Module instances match their definitions’ quantum and classical interfaces.
Action names are unique, targets exist, and the action dependency graph is acyclic.
The expanded graph fits the configured counts of blocks, instances, and occupied cells.
The size check counts the expanded graph from the module hierarchy before any expansion. A small definition graph can expand exponentially, so Bloq refuses an oversized source before spending memory on it.
2. Certification¶
Bloq computes a canonical key from the source’s resolved BLOG text. If the compile cache already holds a finished artifact for that key and configuration, compilation reuses it.
On a cache miss, a hierarchical graph is prepared definition by definition:
Reuse. A definition variant compiled earlier for the same configuration and orientation is reused, including across different root programs.
Link. The root geometry is linked once. Only missing definition variants materialize descendant geometry, join connected ports, and qualify action names by instance path.
Certify. Each child definition’s public interface is checked: every named readout must close before its live outputs. The root is checked again after composition, because a new connection can make a locally valid readout unsafe.
A local graph without modules skips the first two steps. The composition algorithm is still evolving. Modules describes the authoring model it implements.
3. Correlations¶
This stage computes the logical side of the program. It first builds the guarded topology: the reachable assignments of every selector and structural branch, and the local shape of each block under each assignment. Reachability here describes Boolean control, not the probability of a quantum outcome. If one selector is \(a\) and another is \(\neg a\), the planner does not treat all four joint choices as reachable.
The general composed-surface planner builds the correlation space by seam elimination with Boolean-guarded coefficients, plans named readouts in causal waves, and derives terminal frame equations. It produces these recipes:
Recipe |
Contents |
|---|---|
Named readout |
A surface for the value, earlier corrected values it folds in, and its feedback terms |
Terminal frame |
One equation per output axis, with references to later frame bits |
Logical readout |
A closed surface, such as a memory or stability observable |
Planning finishes before any physical work starts. Later stages consume this plan and never revisit the correlation space. Correlation Surfaces explains the algorithm.
4. Placement¶
Placement decides how each patch is realized physically:
Schedules. Patches joined by spatial pipes need compatible syndrome extraction schedules. Bloq groups each spatial component and selects compatible compact, padded, or wall schedules for it.
Walks. Adjacent walks on the same source layer with the same movement share one quantum node. Their templates merge tick by tick, so slides and glides run together while preserving each patch’s measurement records.
Reservations. T-resource spill cells are reserved against the union of all alternatives that can occupy them.
Spatial Ports. A spatial Port expands into an inferred cube and a temporal Port, with explicit provenance for the substituted qubits.
Coordinates. A block at \((x,y)\) is placed at physical offset \((x,y)\cdot(2d+2)\). Coordinate overflow is a typed error.
Bloq places each distinct local case once. Joint assignments of independent choices are not expanded, so placement work follows the number of distinct local shapes rather than \(2^s\) for \(s\) selectors.
5. Templates¶
This stage builds and places the physical circuits.
Build templates once. Each block has a signature: its kind, round count, connectivity, boundary bases, schedule, and T-surgery side. Bloq compiles one template per distinct signature and caches it. A template holds:
the fault-tolerant physical circuit;
its internal detectors, derived from the circuit’s own stabilizer flows;
its boundary flows, the flows it leaves open for neighbors to close;
its observable gateway, which maps a local Pauli pattern to the template’s measurement records.
A selective cap has one template per basis. A T block has cultivation and escape templates, or the configured ideal preparation.
Place instances. An instance places a template at an offset for one source block. Two instances of the same template share circuit data but own distinct measurement records. Structural branches become guarded instance membership rather than separate subgraphs.
Compose checks. Bloq composes the boundary flows of adjacent instances. Each flow that closes becomes a detector, or a retry check inside a T retry region. Detector recipes that repeat across the program are stored once in a shared bundle and referenced by each use. Template-internal detectors are not recomposed per instance.
The number of templates depends on the variety of blocks, not on distance or program size. Each template’s circuit grows with distance: a patch has \(O(d^2)\) qubits and an ordinary cube runs \(d\) rounds.
6. Readouts¶
This stage binds each planned recipe to physical records. For every block
that a planned surface touches, Bloq reconstructs the surface’s local Pauli
pattern and asks that instance’s gateway for the records that realize it. The
records of all blocks combine into one complete Observable node per named
readout or output axis. That node carries both the raw parity and the
corrected value. The decoder estimates the difference between them.
The source’s classical behavior becomes IR nodes:
Source behavior |
IR representation |
|---|---|
Named logical measurement |
Raw |
Earlier corrected value in a recipe |
|
Pauli feedback |
|
Boolean expression |
|
Measurement-basis selection |
Guarded quantum alternatives, selected by corrected values |
Shot rejection |
|
Retried T preparation |
|
A record in an alternative that was not taken is unavailable, and only an accepted retry attempt exports its records and resource patch. The compiler additionally checks that the emitted dependency graph is acyclic before accepting its result.
7. Finalization¶
Finalization turns the assembled pieces into one program:
Bind the logical interface. Record which instances own each input and output cut. Planning state is released after this step.
Order occupancy. Add ordering edges so that a qubit is reused only after its previous owner finishes. Alternatives may share qubits only when their guards cannot hold together.
Optimize. Simplify the classical dependency graph while preserving activation guards, selectors, retry roots, and fold roles. Infer each cut’s logical operators from the optimized IR.
Check the layout. Confirm that no two coexisting instances claim the same physical qubit at the same time.
The result records the code distance and construction convention as metadata.