Python API Reference

The bloq namespace provides the main workflow: author or load a BlockGraph, compile it to Bloq, then emit a circuit or lower the program for VM verification. Import bloq.ir for the concrete types returned by IR accessors. These are the same native objects, with no conversion layer.

This page groups signatures and generated docstrings by task. For a complete first program, use the quickstart.

Compiled-program inspection types and exchange-format constants.

Use these types when inspecting a bloq.Bloq, matching node or circuit variants, or writing a custom backend. They are the same native objects returned by program accessors; importing this namespace adds no wrappers or conversions.

Examples

>>> import bloq
>>> from bloq.ir import CircuitOp, RegionKind
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> isinstance(program.template(0).circuit.ops()[0], CircuitOp)
True
>>> program.regions_of(RegionKind.RepeatUntilSuccess)
[]

Compilation

compile returns a Bloq program at an odd code distance in 3..=255. It accepts both local and hierarchical sources through BlockGraph. Pass validate=True to request a full IR audit after compilation; required local checks run in either case.

The free compile function shares a process-wide template cache with no automatic eviction. Use clear_compile_cache between large distance sweeps, or a CompileContext when a Python object should own a fixed configuration and private cache. A context can serve concurrent callers. Budget overrides use limits={"FIELD": count}; None disables that field’s limit.

func bloq.compile

compile(graph: BlockGraph, distance: int = 3, *, prepare_t_with_mpps: bool = False, validate: bool = False, limits: Mapping[str, int | None] | None = None) → Bloq

Compiles graph into a Bloq IR program with a one-shot context. Circuit templates are still cached process-wide, so repeated calls at one distance stay warm.

Use CompileContext when one object should own the configuration and cache lifetime instead of sharing the process-global cache.

Parameters:
graph: BlockGraph

The block graph to compile.

distance: int = 3

The odd code distance to compile at, in 3..=255.

prepare_t_with_mpps: bool = False

Use compact T-source preparation with one stabilizer MPP instead of MSC-LS cultivation.

validate: bool = False

Explicitly audit the compiled IR using the configured Boolean limits. Defaults to False.

limits: Mapping[str, int | None] | None = None

Compiler budget overrides keyed by field name. Non-negative counts impose a budget, None disables it, and omitted fields keep their defaults. See the field list at https://bloqec.com/docs/dev/api/rust/bloq_graph/struct.ModuleCertificationLimits.html.

Raises:
  • CompileError – If compilation fails.

  • InvalidArgumentError – If the distance or a limit field is invalid.

  • OverflowError – If a limit count is negative or exceeds usize.

Emits:
CompileWarning: Once per advisory the compile recorded — currently a

spatial Hadamard pipe under the fixed-bulk convention, whose effective distance can be lower than the requested code distance.

Examples

>>> import bloq
>>> graph = bloq.GalleryItem.X_MEMORY.load()
>>> bloq.compile(graph, distance=3)
<Bloq nodes=2 edges=1 qubits=17>

class bloq.CompileContext

class CompileContext(distance: int = 3, *, prepare_t_with_mpps: bool = False, limits: Mapping[str, int | None] | None = None)

A reusable compilation context with a fixed configuration and a private template cache. The free compile function instead shares a process-global cache; use a context when its cache lifetime should follow one Python object.

compile releases the GIL and takes a shared receiver, so one context can serve several threads at once — the template cache is internally synchronized.

Examples

>>> import bloq
>>> context = bloq.CompileContext(distance=3)
>>> program = context.compile(bloq.GalleryItem.X_MEMORY.load())
>>> program.metadata[bloq.ir.CODE_DISTANCE_METADATA_KEY]
3

meth bloq.CompileContext.compile

compile(graph: BlockGraph, *, validate: bool = False) → Bloq

Compiles graph into a Bloq IR program.

Parameters:
graph: BlockGraph

The block graph to compile.

validate: bool = False

Explicitly audit the resulting IR, using this context’s Boolean limits. Defaults to False; compilation always performs its required local checks.

Raises:

CompileError – If compilation fails.

Emits:
CompileWarning: Once per advisory the compile recorded — currently

a spatial Hadamard pipe under the fixed-bulk convention, whose effective distance can be lower than the requested code distance.

Examples

>>> import bloq
>>> context = bloq.CompileContext(distance=3)
>>> context.compile(bloq.GalleryItem.X_MEMORY.load())
<Bloq nodes=2 edges=1 qubits=17>
>>> context.compile(bloq.GalleryItem.CNOT.load())  # reuses cached templates
<Bloq nodes=... edges=... qubits=65>

attr bloq.CompileContext.distance

distance

The fixed code distance used by this context.

attr bloq.CompileContext.prepare_t_with_mpps

prepare_t_with_mpps

Whether this context uses compact T-source MPP preparation.

func bloq.clear_compile_cache

clear_compile_cache() → None

Drops every circuit template cached by compile, releasing their memory.

compile caches templates process-wide and never evicts them, so a process that compiles at many code distances — a distance sweep, say — keeps every distance’s templates resident. Call this between phases of such a run to give the memory back; the next compile simply refills the cache.

Compilations already in flight on other threads are unaffected.

Examples

>>> import bloq
>>> bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
<Bloq nodes=2 edges=1 qubits=17>
>>> bloq.clear_compile_cache()
>>> bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)  # recompiles
<Bloq nodes=2 edges=1 qubits=17>

func bloq.is_valid_distance

is_valid_distance(distance: int) → bool

Whether distance is a code distance this compiler accepts: odd and in 3..=255.

Use it to filter a sweep before compiling. Negative and arbitrarily large integers return False; non-integers raise TypeError.

Parameters:
distance: int

The candidate code distance.

Examples

>>> import bloq
>>> [d for d in (1, 2, 3, 4, 1000) if bloq.is_valid_distance(d)]
[3]

Clifford proxies

Clifford proxies replace T resources with perfect input ports and pin selective sites to measurement arms. Supply the pins explicitly, or use the random helper with a seed for reproducibility. These programs support circuit-distance analysis; they do not verify the original non-Clifford computation or replace structural branch selection.

func bloq.compile_clifford_proxy

compile_clifford_proxy(graph: BlockGraph, pins: collections.abc.Sequence[bool], distance: int = 3, *, prepare_t_with_mpps: bool = False, limits: Mapping[str, int | None] | None = None) → Bloq

Compiles graph with every dynamic element replaced by a Clifford stand-in — a distance oracle, not a semantics oracle. Each selective block is statically pinned to one measurement arm by the corresponding pins bit (deterministic block order, one bit per selective site); T blocks become perfect input ports. The result suits Stim distance searches such as shortest_graphlike_error.

pins carries one bit per selective site in deterministic block order; pass an empty list for a graph with no selective blocks.

Both this function and compile_random_clifford_proxy accept simple and hierarchical block graphs. The detector-slice proxy remains an editor view and retains T regions, so it is not a Stim distance-search circuit.

Parameters:
graph: BlockGraph

The block graph to compile.

pins: collections.abc.Sequence[bool]

One bit per selective site in deterministic block order, pinning each to a measurement arm; empty when the graph has no selective blocks.

distance: int = 3

The odd code distance to compile at, in 3..=255.

prepare_t_with_mpps: bool = False

Use compact T-source preparation with one stabilizer MPP instead of MSC-LS cultivation.

limits: Mapping[str, int | None] | None = None

Compiler budget overrides; non-negative counts impose a budget, None disables it, and omitted fields keep their defaults.

Raises:
  • CompileError – If compilation fails.

  • InvalidArgumentError – If the distance or a limit field is invalid.

  • OverflowError – If a limit count is negative or exceeds usize.

Emits:
CompileWarning: Once per advisory the compile recorded — currently a

spatial Hadamard pipe under the fixed-bulk convention, whose effective distance can be lower than the requested code distance.

Examples

>>> import bloq
>>> graph = bloq.GalleryItem.X_MEMORY.load()
>>> bloq.compile_clifford_proxy(graph, [], distance=3).quantum_node_count
1

func bloq.compile_random_clifford_proxy

compile_random_clifford_proxy(graph: BlockGraph, distance: int = 3, *, prepare_t_with_mpps: bool = False, seed: int | None = None, limits: Mapping[str, int | None] | None = None) → Bloq

Compiles one random static Clifford proxy path. Shared selective controls are sampled jointly; the seed is stored under CLIFFORD_PROXY_SEED_METADATA_KEY.

Parameters:
graph: BlockGraph

The block graph to compile.

distance: int = 3

The odd code distance to compile at, in 3..=255.

prepare_t_with_mpps: bool = False

T preparation option; proxy T blocks remain ports.

seed: int | None = None

Reproducible path seed; None generates one.

limits: Mapping[str, int | None] | None = None

Compiler budget overrides; non-negative counts impose a budget, None disables it, and omitted fields keep their defaults.

Source authoring

BlockGraph owns source geometry, actions, and module definitions. Its BLOG load/save operations retain authored hierarchy; compilation consumes that same graph representation. Call flatten() only when an independent flat projection is needed, such as for an explicit port-filling experiment.

Use ActionDag and expressions for named measurements, feedback, and control. GalleryItem.load() supplies reusable examples. The BLOG format describes the corresponding source syntax.

class bloq.BlockGraph

class BlockGraph

A graph of surface code blocks connected by pipes.

Blocks sit at integer lattice positions; pipes are lattice-surgery connections between adjacent blocks. Build one incrementally with add_block / add_pipe, load a ready-made graph from GalleryItem, or parse .blog text with parse_blog.

Examples

>>> from bloq import BlockGraph, Block, Pipe
>>> graph = BlockGraph()
>>> graph.add_block(Block((0, 0, 0), "ZXZ"))
(0, 0, 0)
>>> graph.add_block(Block((0, 0, 1), "ZXZ"))
(0, 0, 1)
>>> graph.add_pipe(Pipe((0, 0, 0), "+Z"))
>>> graph.block_count, graph.pipe_count
(2, 1)
>>> graph.validate()

meth bloq.BlockGraph.definition

static definition(name: str, body: BlockGraph, *, inputs: dict[str, tuple[int, int, int]] | None = None, outputs: dict[str, tuple[int, int, int]] | None = None, bit_inputs: collections.abc.Sequence[str] | None = None, bit_outputs: dict[str, Expr | str] | None = None, actions: collections.abc.Sequence[Action] | None = None, resources: Mapping[str, str] | None = None) → BlockGraph

Copies a graph into a reusable module definition. Omitted interface arguments retain the body’s existing declarations. Quantum port dictionaries retain insertion order; positions name local Port blocks. Supplying inputs or outputs replaces the quantum interface. Child instances and connections are retained. Validate the completed hierarchy with from_definitions.

Parameters:
name: str

Definition name; use main for the executable root.

body: BlockGraph

Graph containing local geometry, actions, and child instances.

inputs: dict[str, tuple[int, int, int]] | None = None

Names and positions of quantum input Ports.

outputs: dict[str, tuple[int, int, int]] | None = None

Names and positions of quantum output Ports.

bit_inputs: collections.abc.Sequence[str] | None = None

Classical names supplied by the parent.

bit_outputs: dict[str, Expr | str] | None = None

Exported expressions or local/child value names.

actions: collections.abc.Sequence[Action] | None = None

Optional replacement actions, using the declared bit inputs.

resources: Mapping[str, str] | None = None

Quantum port resource types; unspecified ports use data.

Raises:

meth bloq.BlockGraph.from_definitions

static from_definitions(definitions: collections.abc.Sequence[BlockGraph], *, limits: Mapping[str, int | None] | None = None) → BlockGraph

Assembles module definitions into a validated hierarchy rooted at main. Each definition is stored once; input graphs remain independent. Definitions must be local graphs without their own helper libraries.

Parameters:
definitions: collections.abc.Sequence[BlockGraph]

Reusable definitions and one executable main.

limits: Mapping[str, int | None] | None = None

Source-analysis and expansion budget overrides.

Raises:

BlockGraphError – If names, interfaces, seams, geometry, or dependencies are invalid.

meth bloq.BlockGraph.from_text

static from_text(text: str, *, limits: Mapping[str, int | None] | None = None) → BlockGraph

Parses .blog text into a block graph, retaining module definitions, instances, interfaces, and connections. This is the same native constructor as Rust’s BlockGraph::from_text. Use load() to resolve imports relative to a file.

Parameters:
text: str

The .blog source text.

limits: Mapping[str, int | None] | None = None

Source-analysis and module-expansion budget overrides. Use non-negative counts or None for unlimited; compilation overrides are passed separately to compile.

Raises:
  • ParseError – If text is not valid .blog.

  • InvalidArgumentError – If a limit field is unknown.

  • OverflowError – If a limit count is negative or exceeds usize.

meth bloq.BlockGraph.load

static load(path: str | os.PathLike | pathlib.Path, *, limits: Mapping[str, int | None] | None = None) → BlockGraph

Loads a .blog file through Rust’s native BlockGraph::load constructor, resolving module imports relative to each file.

Like from_text, retains the module hierarchy. Both simple and hierarchical graphs are accepted by compile.

Parameters:
path: str | os.PathLike | pathlib.Path

A filesystem path, including pathlib.Path objects.

limits: Mapping[str, int | None] | None = None

Source-analysis and module-expansion budget overrides. Use non-negative counts or None for unlimited; the same limits apply to each imported hierarchy.

Raises:
  • OSError – If the root file or an imported file cannot be read.

  • ParseError – If BLOG parsing or module resolution fails.

  • BlockGraphError – If graph structure is invalid.

  • InvalidArgumentError – If a limit field is unknown.

  • OverflowError – If a limit count is negative or exceeds usize.

meth bloq.BlockGraph.action_graph

action_graph() → ActionDag

Returns an independent snapshot of the current source action DAG.

Local structural edits refresh the cached DAG. is_analyzed says whether correlation support dependencies are present. For child instances, call flatten() explicitly to inspect the combined action program.

meth bloq.BlockGraph.actions

actions() → list[Action]

The graph’s actions as structured Action values; str(action) renders the BLOG statement (positions, not block ids).

meth bloq.BlockGraph.add_action

add_action(action: Action) → None

Appends one structured action, rederiving measurement surfaces and the action DAG.

Parameters:
action: Action

The structured action to append.

Raises:

BlockGraphError – If action semantics, measurement-surface derivation, or the resulting dependency DAG is invalid.

meth bloq.BlockGraph.add_actions_from_text

add_actions_from_text(text: str) → None

Appends actions parsed from BLOG action-statement text, e.g. "m = measure 0 -> +Z". Block IDs refer to get_block_id values.

Parameters:
text: str

BLOG action-statement text; numeric block IDs refer to get_block_id values.

Raises:
  • ParseError – If text is not valid action-statement syntax.

  • BlockGraphError – If action semantics, measurement-surface derivation, or the resulting dependency DAG is invalid.

Examples

>>> from bloq import BlockGraph, Block
>>> graph = BlockGraph()
>>> graph.add_block(Block((0, 0, 0), "ZXZ"))
(0, 0, 0)
>>> graph.add_actions_from_text("m = measure 0")
>>> [str(a) for a in graph.actions()]
['m = measure [0, 0, 0]']

meth bloq.BlockGraph.add_block

add_block(block: Block) → tuple[int, int, int]

Adds a block, returning its position. Raises BlockGraphError if the position is occupied.

Parameters:
block: Block

The block to add.

meth bloq.BlockGraph.add_branches

add_branches(branches: collections.abc.Sequence[Branch], *, pipes: collections.abc.Sequence[Pipe] | None = None, actions: collections.abc.Sequence[Action] | None = None) → None

Attaches branches, shared seams, and additional actions in one edit. Each branch supplies its own resolve condition. Existing actions remain. The graph is unchanged if geometry or action validation fails.

Parameters:
branches: collections.abc.Sequence[Branch]

Named branches with explicit false and true arms.

pipes: collections.abc.Sequence[Pipe] | None = None

Shared pipes joining arm boundaries to the common graph or other branches. They are stored once, outside the arms.

actions: collections.abc.Sequence[Action] | None = None

Additional actions, including measurements used by selectors.

Raises:

BlockGraphError – If geometry, interfaces, names, or actions are invalid.

meth bloq.BlockGraph.add_instance

add_instance(name: str, definition: str, translation: tuple[int, int, int] = (0, 0, 0), *, rotation: tuple[UDirection | str, int] | None = None) → None

Places a named child definition, rotating before translating. The completed hierarchy checks names, geometry, and supported orientations.

Parameters:
name: str

Instance name in this parent.

definition: str

Reusable definition name.

translation: tuple[int, int, int] = (0, 0, 0)

Placement in the parent’s lattice coordinates.

rotation: tuple[UDirection | str, int] | None = None

Optional axis and angle in degrees, such as ("Z", 180).

Raises:

InvalidArgumentError – If the axis or rotation angle is invalid.

meth bloq.BlockGraph.add_pipe

add_pipe(pipe: Pipe) → None

Adds a pipe. Raises BlockGraphError if an endpoint is missing or the pipe already exists.

Parameters:
pipe: Pipe

The pipe to add.

meth bloq.BlockGraph.analyze_action_graph

analyze_action_graph(*, limits: Mapping[str, int | None] | None = None) → ActionDag

Derives an independent DAG including correlation support dependencies.

Accepts local graphs and authored module hierarchies without changing the source. Hierarchies use the compiler’s module linker and correlation composition. owners() identifies each action’s definition and instance. Continuing branches use guarded causal readout planning.

Parameters:
limits: Mapping[str, int | None] | None = None

Source-analysis budget overrides, as accepted by from_text.

Raises:
  • BlockGraphError – If module validation, readout analysis or resource limits fail.

  • InvalidArgumentError – If a limit field is unknown.

  • OverflowError – If a limit count is negative or exceeds usize.

Examples

>>> import bloq
>>> source = bloq.GalleryItem.T_GATE.load()
>>> dag = source.analyze_action_graph()
>>> dag.is_analyzed
True

meth bloq.BlockGraph.bind

bind(source: str, target: str) → None

Supplies a parent value or child bit output to a child classical input. For example, bind("read.result", "correct.flip") creates a dependency between those instances. The completed hierarchy validates the binding.

Raises:

InvalidArgumentError – If a qualified endpoint is malformed.

meth bloq.BlockGraph.bind_modules

bind_modules(source: str, target: str) → None

Binds a parent value or child bit output to a child’s classical input. Replaces the current binding and removes an unused exposed parent input.

Raises:

BlockGraphError – If values or dependencies are invalid; the graph is unchanged.

meth bloq.BlockGraph.blocks

blocks() → list[Block]

Blocks authored in this definition’s local body, excluding child instances.

meth bloq.BlockGraph.can_place_block

can_place_block(block: Block) → bool

Returns True when block can be placed without overlap.

Parameters:
block: Block

The candidate block to test.

meth bloq.BlockGraph.clear_actions

clear_actions() → None

Removes all actions from the graph.

meth bloq.BlockGraph.connect

connect(source: tuple[int, int, int] | str, target: tuple[int, int, int] | str, *, hadamard: bool = False) → None

Connects a child quantum output to an input or a parent-local block. Endpoints are local position tuples or strings such as gate.q_out. At least one endpoint must belong to an instance. Connections do not route geometry; the completed hierarchy checks placement and boundary bases.

Raises:

InvalidArgumentError – If endpoint syntax is invalid or both endpoints are local.

meth bloq.BlockGraph.connect_modules

connect_modules(output: str, input: str, *, align: bool = True, compact: bool = True, hadamard: bool = False) → int

Aligns and docks named child ports, joining all other touching compatible ports. The input instance’s connected group moves together. Endpoint Hadamards are preserved; obstructed compaction retains connection cubes.

Parameters:
output: str

Child output name, such as child0.control_out.

input: str

Child input name, such as child1.control_in.

align: bool = True

Align the input group’s selected port to the output.

compact: bool = True

Prefer direct seams over parent connection cubes.

hadamard: bool = False

Extra basis change at the selected seam.

Returns:

Number of port pairs joined.

Raises:

BlockGraphError – If ports, types, faces, or placement are invalid; the graph is unchanged.

meth bloq.BlockGraph.degree

degree(pos: tuple[int, int, int]) → int

The number of pipes attached to the block at pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.export_gltf

export_gltf(path: str | os.PathLike | pathlib.Path, pipe_length: float = 2.0, stabilizer: StabilizerGenerator | collections.abc.Sequence[int] | None = None, pop_faces_at_directions: collections.abc.Sequence[Direction | str] | None = None, pop_faces_at_blocks: collections.abc.Sequence[tuple[tuple[int, int, int], Direction | str]] | None = None, pop_faces_at_pipes: collections.abc.Sequence[tuple[tuple[int, int, int], tuple[int, int, int], Direction | str]] | None = None, module_view: bool = False) → None

Exports the graph as a .gltf scene, optionally overlaying a stabilizer row. Set module_view=True to color an authored hierarchy by definition.

Parameters:
path: str | os.PathLike | pathlib.Path

Filesystem path to write the .gltf file to.

pipe_length: float = 2.0

Rendered pipe length in scene units. Defaults to 2.0.

module_view: bool = False

Color by module definition without changing the hierarchy. Cannot be combined with a stabilizer overlay.

stabilizer: StabilizerGenerator | collections.abc.Sequence[int] | None = None

Optional generator, or indices of logical generators whose phase-free product supplies the displayed correlation support.

pop_faces_at_directions: collections.abc.Sequence[Direction | str] | None = None

Signed lattice directions whose outward faces are removed, for example ["-Y"].

pop_faces_at_blocks: collections.abc.Sequence[tuple[tuple[int, int, int], Direction | str]] | None = None

(position, face_direction) pairs selecting individual block faces.

pop_faces_at_pipes: collections.abc.Sequence[tuple[tuple[int, int, int], tuple[int, int, int], Direction | str]] | None = None

(u, v, face_direction) triples selecting individual pipe faces.

Raises:

OSError – If the file cannot be written.

meth bloq.BlockGraph.export_html_viewer

export_html_viewer(path: str | os.PathLike | pathlib.Path, pipe_length: float = 2.0, stabilizer: StabilizerGenerator | collections.abc.Sequence[int] | None = None, pop_faces_at_directions: collections.abc.Sequence[Direction | str] | None = None, pop_faces_at_blocks: collections.abc.Sequence[tuple[tuple[int, int, int], Direction | str]] | None = None, pop_faces_at_pipes: collections.abc.Sequence[tuple[tuple[int, int, int], tuple[int, int, int], Direction | str]] | None = None, module_view: bool = False) → None

Exports the graph as a self-contained HTML viewer page (the model-viewer renderer is loaded from a CDN, so viewing needs network). Set module_view=True for the editor’s definition colors and module legend.

Parameters:
path: str | os.PathLike | pathlib.Path

Filesystem path to write the HTML file to.

pipe_length: float = 2.0

Rendered pipe length in scene units. Defaults to 2.0.

module_view: bool = False

Color by module definition without changing the hierarchy. Cannot be combined with a stabilizer overlay.

stabilizer: StabilizerGenerator | collections.abc.Sequence[int] | None = None

Optional generator, or indices of logical generators whose phase-free product supplies the displayed correlation support.

pop_faces_at_directions: collections.abc.Sequence[Direction | str] | None = None

Signed lattice directions whose outward faces are removed, for example ["-Y"].

pop_faces_at_blocks: collections.abc.Sequence[tuple[tuple[int, int, int], Direction | str]] | None = None

(position, face_direction) pairs selecting individual block faces.

pop_faces_at_pipes: collections.abc.Sequence[tuple[tuple[int, int, int], tuple[int, int, int], Direction | str]] | None = None

(u, v, face_direction) triples selecting individual pipe faces.

Raises:

OSError – If the file cannot be written.

meth bloq.BlockGraph.fill_ports_auto

fill_ports_auto() → list[tuple[BlockGraph, list[StabilizerGenerator]]]

Builds compatible static boundary fills, returning (closed_graph, stabilizer_generators) pairs.

Port, T, and Selective sites use full compatible boundary support. Variants retain selected measurement records and aliases, and remove feedback and resolves for filled caps.

filled_graphs() is the same thing without the generators, for the common case of only wanting the closed graphs. Call flatten() first for authored module interfaces or child instances.

Raises:

BlockGraphError – If a boundary cannot be filled, or postselection or a structural branch needs an omitted measurement record.

meth bloq.BlockGraph.filled_graphs

filled_graphs() → list[BlockGraph]

The graphs from fill_ports_auto(), without their selecting generators. Call flatten() first for authored module interfaces or child instances.

Raises:

BlockGraphError – If the ports cannot be filled.

Examples

>>> import bloq
>>> filled = bloq.GalleryItem.BELL_STATE.load().flatten().filled_graphs()
>>> all(not graph.is_open for graph in filled)
True

meth bloq.BlockGraph.flatten

flatten(*, limits: Mapping[str, int | None] | None = None) → BlockGraph

Expands module instances into one independent graph for geometry, boundary filling, or flat source analysis. Compilation preserves the hierarchy and does not require this conversion.

Parameters:
limits: Mapping[str, int | None] | None = None

Source-expansion budget overrides. Use non-negative counts or None for unlimited; omitted fields retain their defaults.

Raises:

BlockGraphError – If expansion cannot produce a valid flat graph.

meth bloq.BlockGraph.flip_xz_basis

flip_xz_basis() → BlockGraph

Returns a new graph with X/Z bases flipped (topology-preserving). Call flatten() first for authored module interfaces or child instances.

Raises:

BlockGraphError – If the basis flip cannot be applied.

meth bloq.BlockGraph.get_block

get_block(pos: tuple[int, int, int]) → Block | None

Returns the block at pos, or None if absent.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.get_block_id

get_block_id(pos: tuple[int, int, int]) → int | None

Returns the internal node ID for the block at pos, or None.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.get_pipe

get_pipe(u: tuple[int, int, int], v: tuple[int, int, int]) → Pipe | None

Returns the pipe between u and v, or None if absent.

Parameters:
u: tuple[int, int, int]

One endpoint position (x, y, z).

v: tuple[int, int, int]

The other endpoint position (x, y, z).

meth bloq.BlockGraph.has_actions

has_actions() → bool

True if the graph carries any actions.

meth bloq.BlockGraph.has_block_at

has_block_at(pos: tuple[int, int, int]) → bool

True if a block occupies pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.has_pipe_between

has_pipe_between(u: tuple[int, int, int], v: tuple[int, int, int]) → bool

True if a pipe connects u and v.

Parameters:
u: tuple[int, int, int]

One endpoint position (x, y, z).

v: tuple[int, int, int]

The other endpoint position (x, y, z).

meth bloq.BlockGraph.module

module(name: str, *, limits: Mapping[str, int | None] | None = None) → BlockGraph

Extracts a named definition as an independent graph, retaining its reachable helper definitions and naming its executable root main. The copy can be edited, saved, pickled, and compiled independently.

Parameters:
name: str

The definition name.

limits: Mapping[str, int | None] | None = None

Source-analysis and expansion budget overrides.

Raises:
  • KeyError – If the definition is absent.

  • BlockGraphError – If its independent hierarchy cannot be constructed.

meth bloq.BlockGraph.neighbors

neighbors(pos: tuple[int, int, int]) → list[Block]

All blocks directly connected to the block at pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.occupied_positions

occupied_positions() → list[tuple[int, int, int]]

Local lattice cells reserved by blocks (multi-cell blocks contribute their full footprint).

meth bloq.BlockGraph.pipes

pipes() → list[Pipe]

Pipes authored in this definition’s local body, excluding child instances.

meth bloq.BlockGraph.place_module

place_module(name: str, definition: str, translation: tuple[int, int, int] | None = None, *, rotation: tuple[UDirection | str, int] | None = None) → tuple[int, int, int]

Places a module instance and exposes its quantum and classical interface. With no translation, places it beside the current geometry. The graph must contain the named definition; input graphs remain independent.

Parameters:
name: str

New instance name.

definition: str

Definition already stored in this graph.

translation: tuple[int, int, int] | None = None

Optional explicit lattice placement.

rotation: tuple[UDirection | str, int] | None = None

Optional axis and angle, such as ("Z", 180).

Returns:

The instance’s translation.

Raises:

BlockGraphError – If placement, names, or interfaces are invalid; the graph is unchanged.

meth bloq.BlockGraph.placement_error

placement_error(block: Block) → str | None

Why block cannot be placed, or None when it can.

The message add_block would have raised, without raising it — for callers reporting the reason rather than just refusing.

Parameters:
block: Block

The candidate block to test.

Examples

>>> import bloq
>>> graph = bloq.BlockGraph()
>>> graph.add_block(bloq.Block((0, 0, 0), "ZXZ"))
(0, 0, 0)
>>> graph.placement_error(bloq.Block((0, 0, 1), "ZXZ")) is None
True
>>> "occupied" in graph.placement_error(bloq.Block((0, 0, 0), "ZXZ"))
True

meth bloq.BlockGraph.positions

positions() → list[tuple[int, int, int]]

Positions of this definition’s local blocks, excluding child instances.

meth bloq.BlockGraph.project_branches

project_branches(assignments: collections.abc.Sequence[tuple[tuple[int, int, int], bool]]) → BlockGraph

Projects every structural branch to a static true or false arm.

The returned graph has no branch actions and can be passed to stabilizers(). Every branch target must appear exactly once. Call flatten() first for authored module interfaces or child instances.

Parameters:
assignments: collections.abc.Sequence[tuple[tuple[int, int, int], bool]]

(target_position, value) pairs for every branch.

Raises:

BlockGraphError – If a target is unknown, duplicated, or omitted, or the branch regions are invalid.

meth bloq.BlockGraph.randomly_resolve_selectives

randomly_resolve_selectives(seed: int | None = None) → tuple[BlockGraph, dict[Block, Block]]

Resolves all selective blocks by randomly choosing a measurement basis. Returns (resolved_graph, replacements) where replacements maps each original selective block to its resolved block. Deterministic when seed is given.

If any selective is resolved, the returned graph is structure-only and has no actions, including structural branches. Project branches first when a concrete conditional topology is required. Call flatten() first for authored module interfaces or child instances.

Parameters:
seed: int | None = None

Optional RNG seed; when given, resolution is deterministic. Defaults to None (nondeterministic).

meth bloq.BlockGraph.remove_block

remove_block(pos: tuple[int, int, int]) → Block | None

Removes and returns the block at pos, or None if absent.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

meth bloq.BlockGraph.remove_pipe

remove_pipe(u: tuple[int, int, int], v: tuple[int, int, int]) → Pipe | None

Removes and returns the pipe between u and v, or None if absent.

Parameters:
u: tuple[int, int, int]

One endpoint position (x, y, z).

v: tuple[int, int, int]

The other endpoint position (x, y, z).

meth bloq.BlockGraph.rotate_about_origin

rotate_about_origin(axis: UDirection | str, quarter_turns: int) → BlockGraph

Returns a new graph rotated about the origin around axis by quarter_turns 90-degree steps. Discards actions. Call flatten() first for authored module interfaces or child instances.

Parameters:
axis: UDirection | str

A UDirection or its axis letter ("X" / "Y" / "Z").

quarter_turns: int

Number of 90-degree steps; may be negative.

Raises:

meth bloq.BlockGraph.save

save(path: str | os.PathLike | pathlib.Path) → None

Writes the graph to a .blog file.

Parameters:
path: str | os.PathLike | pathlib.Path

Filesystem path to write the .blog file to.

Raises:

OSError – If the file cannot be written.

meth bloq.BlockGraph.set_actions

set_actions(actions: collections.abc.Sequence[Action]) → None

Replaces all actions, rederiving measurement surfaces and the action DAG.

Parameters:
actions: collections.abc.Sequence[Action]

The structured actions to install, replacing any existing.

Raises:

BlockGraphError – If action semantics, measurement-surface derivation, or the resulting dependency DAG is invalid.

meth bloq.BlockGraph.set_block_kind

set_block_kind(pos: tuple[int, int, int], kind: BlockKind | str) → None

Replaces the kind of the block at pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

kind: BlockKind | str

A BlockKind or its BLOG spelling.

Raises:

meth bloq.BlockGraph.set_block_tag

set_block_tag(pos: tuple[int, int, int], tag: str) → None

Replaces the tag of the block at pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) lattice position.

tag: str

The new tag string.

Raises:

BlockGraphError – If no block occupies pos.

meth bloq.BlockGraph.set_pipe_hadamard

set_pipe_hadamard(u: tuple[int, int, int], v: tuple[int, int, int], hadamard: bool) → None

Sets whether the pipe between u and v carries a Hadamard.

Parameters:
u: tuple[int, int, int]

One endpoint position (x, y, z).

v: tuple[int, int, int]

The other endpoint position (x, y, z).

hadamard: bool

Whether the pipe carries a Hadamard across the seam.

Raises:

BlockGraphError – If no pipe connects u and v.

meth bloq.BlockGraph.set_pipe_tag

set_pipe_tag(u: tuple[int, int, int], v: tuple[int, int, int], tag: str) → None

Replaces the tag of the pipe between u and v.

Parameters:
u: tuple[int, int, int]

One endpoint position (x, y, z).

v: tuple[int, int, int]

The other endpoint position (x, y, z).

tag: str

The new tag string.

Raises:

BlockGraphError – If no pipe connects u and v.

meth bloq.BlockGraph.set_port_role

set_port_role(pos: tuple[int, int, int], role: str) → None

Assigns a Port’s "auto", "input", "output", or "multiplex" role.

meth bloq.BlockGraph.shift_positions

shift_positions(offset: tuple[int, int, int]) → BlockGraph

Returns a new graph shifted by offset. Call flatten() first for authored module interfaces or child instances.

Parameters:
offset: tuple[int, int, int]

The (x, y, z) amount to shift every position by.

Raises:

meth bloq.BlockGraph.stabilizers

stabilizers() → list[StabilizerGenerator]

Derives the stabilizer generators of the graph’s ZX diagram. Call flatten() first if the graph contains child instances.

Raises:

BlockGraphError – If the stabilizers cannot be derived.

Examples

>>> import bloq
>>> graph = bloq.GalleryItem.X_MEMORY.load()
>>> graph.stabilizers()[0].kind
'logical'

meth bloq.BlockGraph.to_text

to_text() → str

Serializes the graph to .blog text (BLOG 1.0).

meth bloq.BlockGraph.translate_module

translate_module(name: str, offset: tuple[int, int, int], *, compact: bool = True) → tuple[int, int, int]

Translates a connected group and joins touching compatible free ports. Returns the applied offset, including any successful compaction.

Raises:

BlockGraphError – If geometry or interfaces are invalid; the graph is unchanged.

meth bloq.BlockGraph.validate

validate() → None

Validates structural constraints and action semantics.

Raises:

BlockGraphError – If a structural or action-semantic constraint is violated.

meth bloq.BlockGraph.validate_structure

validate_structure() → None

Validates structural constraints only (skips action semantics).

Raises:

BlockGraphError – If a structural constraint is violated.

meth bloq.BlockGraph.with_zero_min_z

with_zero_min_z() → BlockGraph

Returns a new graph shifted so the minimum z-coordinate is zero. Call flatten() first for authored module interfaces or child instances.

Raises:

attr bloq.BlockGraph.block_count

block_count

Number of blocks in this definition’s local body, excluding child instances.

attr bloq.BlockGraph.has_module_structure

has_module_structure

Whether the graph declares module interfaces, instances, or definitions. A leaf with an explicit quantum or classical interface also returns true.

attr bloq.BlockGraph.is_clifford

is_clifford

True when the graph and its reachable instances contain no T blocks.

attr bloq.BlockGraph.is_empty

is_empty

True if the graph and its reachable instances have no blocks.

attr bloq.BlockGraph.is_open

is_open

True when the graph contains at least one port.

attr bloq.BlockGraph.is_rigid

is_rigid

True when every block, including reachable instances, has a statically known kind (no selectives).

attr bloq.BlockGraph.module_names

module_names

Names of all graph definitions, including the root.

attr bloq.BlockGraph.patch_rotation_count

patch_rotation_count

Number of patch-rotation blocks in this definition’s local body.

attr bloq.BlockGraph.pipe_count

pipe_count

Number of pipes in this definition’s local body, excluding child instances.

attr bloq.BlockGraph.port_count

port_count

Number of port blocks in this definition’s local body.

attr bloq.BlockGraph.selective_count

selective_count

Number of selective blocks in this definition’s local body.

attr bloq.BlockGraph.t_count

t_count

Number of T blocks in this definition’s local body.

attr bloq.BlockGraph.walking_count

walking_count

Number of walking blocks in this definition’s local body.

attr bloq.BlockGraph.y_count

y_count

Number of Y blocks in this definition’s local body.

class bloq.Block

class Block(pos: tuple[int, int, int], kind: BlockKind | str, height: str = 'd', tag: str | None = None, role: str = 'auto')

A block placed at a 3D lattice position.

The kind argument accepts a BlockKind or its BLOG spelling ("ZXZ", "T", …).

Examples

>>> from bloq import Block
>>> b = Block((0, 1, 2), "ZXZ")
>>> b.pos
(0, 1, 2)
>>> str(b.kind)
'ZXZ'

attr bloq.Block.height

height

The block’s height as a k*d + n expression of the code distance, in the canonical BLOG spelling ("d", "2d", "d/2", "3d+2").

attr bloq.Block.kind

kind

The block’s kind.

attr bloq.Block.pos

pos

The block’s (x, y, z) lattice position.

attr bloq.Block.role

role

The Port’s "auto", "input", "output", or "multiplex" role; None for non-Ports.

attr bloq.Block.tag

tag

The block’s tag string, or None.

class bloq.BlockKind

class BlockKind

The kind of a block: a cube, a moving block, Y, a fixed measurement, Port, T, or a selective block. Data-carrying kinds are built via the static constructors.

Examples

>>> from bloq import BlockKind
>>> k = BlockKind.cube("ZXZ")
>>> k.is_cube
True
>>> tuple(str(b) for b in k.bases)
('Z', 'X', 'Z')
>>> BlockKind.t().is_clifford
False

meth bloq.BlockKind.cube

static cube(spec: str) → BlockKind

A cube block from its face-basis spelling, e.g. "XZZ".

Parameters:
spec: str

The three face bases as an X/Z string, e.g. "XZZ" (case-insensitive).

Raises:

InvalidArgumentError – If spec is not a valid cube spelling.

meth bloq.BlockKind.measurement

static measurement(basis: Basis | str) → BlockKind

A fixed terminal transversal measurement in the X or Z basis.

Parameters:
basis: Basis | str

A Basis or its "X" / "Z" letter (case-insensitive).

Raises:

InvalidArgumentError – If basis is not X or Z.

meth bloq.BlockKind.parse

static parse(text: str) → BlockKind

Parses a BLOG kind spelling ("XZZ", "X", "Y", "Z", "PORT", "T", "XY", …).

Walking and patch-rotation kinds carry movement data and cannot be spelled as a single token; build them via walking / patch_rotation.

Parameters:
text: str

A BLOG kind token, e.g. "XZZ", "X", "Y", "Z", "PORT", "T", or "XY".

Raises:

InvalidArgumentError – If text is not a valid single-token kind spelling.

meth bloq.BlockKind.patch_rotation

static patch_rotation(basis: Basis | str, movement: tuple[int, int]) → BlockKind

A patch-rotation block from a basis and an (x, y) movement of (+/-1, 0) or (0, +/-1).

Parameters:
basis: Basis | str

A Basis or its "X" / "Z" letter (case-insensitive).

movement: tuple[int, int]

The (x, y) step: (+/-1, 0) or (0, +/-1).

Raises:

InvalidArgumentError – If basis or movement is invalid.

meth bloq.BlockKind.port

static port() → BlockKind

An open port block.

meth bloq.BlockKind.selective

static selective(spec: str) → BlockKind

A selective block from its spelling ("XY", "XZ", or "YZ").

Parameters:
spec: str

The selective spelling: "XY", "XZ", or "YZ".

Raises:

InvalidArgumentError – If spec is not a valid selective spelling.

meth bloq.BlockKind.t

static t() → BlockKind

The non-Clifford T block.

meth bloq.BlockKind.walking

static walking(boundary: str, movement: tuple[int, int]) → BlockKind

A walking block from its boundary spelling (e.g. "ZXZ") and an (x, y) movement of (+/-1, 0), (0, +/-1), or (+/-1, +/-1).

Parameters:
boundary: str

The boundary basis spelling, e.g. "ZXZ" (case-insensitive).

movement: tuple[int, int]

The (x, y) step: (+/-1, 0), (0, +/-1), or (+/-1, +/-1).

Raises:

InvalidArgumentError – If boundary or movement is invalid.

meth bloq.BlockKind.y

static y() → BlockKind

The Y-basis block.

meth bloq.BlockKind.flip_xz_basis

flip_xz_basis() → BlockKind

Returns a new kind with X/Z bases flipped.

attr bloq.BlockKind.bases

bases

The (x, y, z) face bases, when this kind has a fixed basis assignment.

attr bloq.BlockKind.is_clifford

is_clifford

True if this kind is Clifford (everything except T).

attr bloq.BlockKind.is_cube

is_cube

True if this is a cube block.

attr bloq.BlockKind.is_dynamic

is_dynamic

True for kinds whose behavior is resolved at runtime (T, selective).

attr bloq.BlockKind.is_measurement

is_measurement

True if this is a fixed terminal measurement block.

attr bloq.BlockKind.is_patch_rotation

is_patch_rotation

True if this is a patch-rotation block.

attr bloq.BlockKind.is_port

is_port

True if this is an open port block.

attr bloq.BlockKind.is_selective

is_selective

True if this is a selective block.

attr bloq.BlockKind.is_t

is_t

True if this is a T block.

attr bloq.BlockKind.is_walking

is_walking

True if this is a walking (moving) block.

attr bloq.BlockKind.is_y

is_y

True if this is the Y-basis block.

attr bloq.BlockKind.measurement_basis

measurement_basis

The X or Z basis of a fixed measurement block; None for other kinds.

attr bloq.BlockKind.movement

movement

The (x, y) in-plane step of a walking or patch-rotation kind, as passed to walking / patch_rotation; None for kinds that do not move.

Examples

>>> from bloq import BlockKind
>>> BlockKind.walking("ZXZ", (1, 0)).movement
(1, 0)
>>> BlockKind.cube("ZXZ").movement is None
True

class bloq.Pipe

class Pipe(src: tuple[int, int, int], direction: Direction | str, hadamard: bool = False, tag: str | None = None)

A pipe (lattice-surgery connection) from a source block along a direction.

The destination is one lattice step from src along direction, so a pipe is fully described by its source and direction. The direction argument accepts a Direction or its BLOG spelling ("+Z", …).

Examples

>>> from bloq import Pipe
>>> p = Pipe((0, 0, 0), "+Z")
>>> p.src, p.dst
((0, 0, 0), (0, 0, 1))
>>> str(p.direction)
'+Z'

attr bloq.Pipe.direction

direction

The direction the pipe leaves its source block.

attr bloq.Pipe.dst

dst

The destination block position (x, y, z).

attr bloq.Pipe.hadamard

hadamard

True if the pipe applies a Hadamard across the seam.

attr bloq.Pipe.src

src

The source block position (x, y, z).

attr bloq.Pipe.tag

tag

The pipe’s tag string, or None.

class bloq.Action

class Action

A classical action between time steps of a block-graph program.

Construct via the staticmethod builders; most mirror BLOG action statements. branch is the graph-dependent internal form of a named branch resolve. str(action) renders a coordinate form (with positions, not block ids).

Examples

>>> from bloq import Action, Expr
>>> a = Action.measure((0, 0, 0), "m")
>>> a.kind, a.name
('measure', 'm')
>>> let = Action.let("q", Expr.var("m1") ^ Expr.var("m2"))
>>> str(let)
'q = m1 ^ m2'

meth bloq.Action.branch

static branch(target: tuple[int, int, int], condition: Expr | str) → Action

Internal structural resolve action for an existing named branch region. Prefer BLOG resolve <branch-name> if <condition> when authoring one.

Parameters:
target: tuple[int, int, int]

The region’s internal (x, y, z) true-arm key.

condition: Expr | str

The branch condition; an Expr or a variable-name str.

meth bloq.Action.discard_if

static discard_if(expr: Expr | str) → Action

discard if <expr> — post-select the shot away when expr is true.

Parameters:
expr: Expr | str

The predicate; an Expr or a variable-name str.

meth bloq.Action.feedback

static feedback(targets: collections.abc.Sequence[FeedbackTarget | tuple[PauliBasis | str, tuple[int, int, int]]], condition: Expr | str | None = None) → Action

feedback <targets> [if <condition>] — apply Pauli feedback, optionally gated. Targets accept FeedbackTarget instances or (pauli, pos) tuples.

Parameters:
targets: collections.abc.Sequence[FeedbackTarget | tuple[PauliBasis | str, tuple[int, int, int]]]

The feedback targets; FeedbackTarget instances or (pauli, pos) tuples.

condition: Expr | str | None = None

Optional gate expression; an Expr or a variable-name str. Defaults to None (always applied).

Raises:

InvalidArgumentError – If a target’s Pauli letter is invalid.

meth bloq.Action.let

static let(name: str, expr: Expr | str) → Action

let <name> = <expr> — define a named boolean variable.

Parameters:
name: str

The variable name to define.

expr: Expr | str

The defining expression; an Expr or a variable-name str.

meth bloq.Action.measure

static measure(target: MeasureTarget | tuple[int, int, int], name: str) → Action

<name> = measure <target> — bind a measurement outcome variable.

Parameters:
target: MeasureTarget | tuple[int, int, int]

A MeasureTarget or a bare (x, y, z) position (a node).

name: str

The outcome variable name to bind.

meth bloq.Action.resolve

static resolve(target: tuple[int, int, int], condition: Expr | str) → Action

resolve <target> if <condition> — resolve a selective block.

Parameters:
target: tuple[int, int, int]

The (x, y, z) selective block position.

condition: Expr | str

The resolving condition; an Expr or a variable-name str.

meth bloq.Action.with_shift

with_shift(offset: tuple[int, int, int]) → Action

This action with every position shifted by offset.

Parameters:
offset: tuple[int, int, int]

The (x, y, z) amount to shift every position by.

Raises:

InvalidArgumentError – If a shifted position exceeds the 32-bit coordinate range.

attr bloq.Action.branch_target

branch_target

Internal true-arm key of a structural branch action.

attr bloq.Action.condition

condition

the discard if predicate, the resolve or branch condition, or the optional feedback gate.

Type:

Guard expression

attr bloq.Action.expr

expr

Defining expression of a let action.

attr bloq.Action.feedback_targets

feedback_targets

Targets of a feedback action.

attr bloq.Action.kind

kind

"let", "measure", "discard_if", "resolve", "branch", or "feedback".

attr bloq.Action.name

name

Variable name for let and measure actions.

attr bloq.Action.resolve_target

resolve_target

Selective block position of a resolve action.

attr bloq.Action.target

target

Measurement target of a measure action.

class bloq.ActionDag

class ActionDag

A snapshot of source action dependencies.

Returned by BlockGraph.analyze_action_graph(), or by BlockGraph.action_graph() to inspect cached dependencies. Node ids are DAG ordinals indexing actions(). Rendering alone does not analyze the graph.

meth bloq.ActionDag.actions

actions() → list[Action]

Returns the actions in DAG ordinal order.

meth bloq.ActionDag.dependencies

dependencies() → list[tuple[int, int, str]]

Returns (predecessor, consumer, reason) edges in deterministic order.

Reasons are Classical, SelectiveSupport, BranchSupport, FeedbackAnticommutation, or ReadoutParity. Ordinals index actions().

meth bloq.ActionDag.inputs

inputs() → list[str]

Returns the declared external Boolean input names.

meth bloq.ActionDag.owners

owners() → list[tuple[str, str] | None]

Returns (definition_name, instance_path) ownership for each action.

Paths use __ between instances and are empty for the root. Interface bindings belong to their receiving instance. Entries are None for standalone flat graphs without authored module ownership. The list has the same ordinal order as actions().

meth bloq.ActionDag.to_svg

to_svg() → str

Renders a self-contained SVG of the stored dependencies.

Solid arrows show variable dependencies. Dashed arrows show dependencies inferred from correlation support. Full action text and dependency reasons are retained. Rendering does not derive missing dependencies or set times.

Raises:

BlockGraphError – If action syntax, names or dependency cycles are invalid.

attr bloq.ActionDag.is_analyzed

is_analyzed

Whether correlation support dependencies have been analyzed. An empty action program has nothing to derive.

class bloq.Branch

class Branch(name: str, condition: Expr | str, *, on_false: BranchArm, on_true: BranchArm)

A named branch with a corrected selector and two explicitly authored arms. Use BlockGraph.add_branches to attach it with its shared seams and resolve.

attr bloq.Branch.condition

condition

Corrected expression selecting the true arm.

attr bloq.Branch.name

name

Public branch name.

attr bloq.Branch.on_false

on_false

Geometry selected when the condition is false.

attr bloq.Branch.on_true

on_true

Geometry selected when the condition is true.

class bloq.BranchArm

class BranchArm(blocks: collections.abc.Sequence[Block | tuple[tuple[int, int, int], BlockKind | str]], *, pipes: collections.abc.Sequence[Pipe] | None = None)

Geometry for one branch arm, using coordinates in the parent graph. Blocks accept bloq.Block objects or ((x, y, z), kind) pairs. Pipes use bloq.Pipe objects. External seams are passed once to add_branches. Geometry is checked when attached to its parent.

Examples

>>> import bloq
>>> arm = bloq.BranchArm([((0, 0, 1), "Z")])
>>> arm.blocks()[0].pos
(0, 0, 1)

meth bloq.BranchArm.blocks

blocks() → list[Block]

Arm blocks in canonical position order.

meth bloq.BranchArm.pipes

pipes() → list[Pipe]

Arm pipes in canonical endpoint order.

class bloq.MeasureTarget

class MeasureTarget

The target of a measurement action: a node position, or an edge identified by its source position and direction.

Examples

>>> from bloq import MeasureTarget
>>> node = MeasureTarget.node((0, 0, 0))
>>> node.is_edge
False
>>> edge = MeasureTarget.edge((0, 0, 0), "+Z")
>>> edge.is_edge, str(edge.direction)
(True, '+Z')

meth bloq.MeasureTarget.edge

static edge(src: tuple[int, int, int], direction: Direction | str) → MeasureTarget

Measurement of the pipe leaving src in direction.

Parameters:
src: tuple[int, int, int]

The (x, y, z) source block position.

direction: Direction | str

A Direction or its BLOG spelling ("+Z", …).

Raises:

InvalidArgumentError – If direction is not a valid spelling.

meth bloq.MeasureTarget.node

static node(pos: tuple[int, int, int]) → MeasureTarget

Measurement of the block at pos.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) block position to measure.

attr bloq.MeasureTarget.direction

direction

Edge direction; None for node targets.

attr bloq.MeasureTarget.is_edge

is_edge

True for edge targets, False for node targets.

attr bloq.MeasureTarget.pos

pos

Node position, or edge source position.

class bloq.FeedbackTarget

class FeedbackTarget(pauli: PauliBasis | str, pos: tuple[int, int, int], *, direction: Direction | str | None = None)

A Pauli feedback applied to the block at pos.

The pauli argument accepts a PauliBasis or its "X" / "Y" / "Z" letter.

Examples

>>> from bloq import FeedbackTarget
>>> ft = FeedbackTarget("X", (0, 0, 0))
>>> str(ft.pauli), ft.pos
('X', (0, 0, 0))

attr bloq.FeedbackTarget.direction

direction

The outgoing wire direction, or None for a node correction.

attr bloq.FeedbackTarget.pauli

pauli

The feedback Pauli basis.

attr bloq.FeedbackTarget.pos

pos

The target block position (x, y, z).

class bloq.Expr

class Expr

A boolean expression over measurement outcome variables.

Build with Expr.var("m") (or pass a bare str wherever an expression is expected) and compose with ^ (xor), & (and), | (or), ~ (not) — each maps 1:1 to the BLOG expression operators. Python truth testing (bool, if, and, or, not) raises TypeError: outcomes are unknown until execution. Use the bitwise operators to build expressions.

Examples

>>> from bloq import Expr
>>> e = Expr.var("m1") ^ Expr.var("m2")
>>> e.kind, e.op
('binary', 'xor')
>>> [str(o) for o in e.operands()]
['m1', 'm2']

meth bloq.Expr.var

static var(name: str) → Expr

A named variable reference (a measurement outcome or let name).

Parameters:
name: str

The variable name (a measurement outcome or let name).

meth bloq.Expr.operands

operands() → list[Expr]

Direct sub-expressions (empty for kind == "var").

attr bloq.Expr.kind

kind

"var", "unary", or "binary".

attr bloq.Expr.name

name

Variable name (kind == "var" only).

attr bloq.Expr.op

op

Operator name — "not", "xor", "and", or "or" — for unary and binary expressions.

class bloq.GalleryItem

class GalleryItem(*values)

A built-in example block graph for analysis or compilation.

Members use the compiler’s gallery ids.

Examples

>>> import bloq
>>> graph = bloq.GalleryItem.CNOT.load()
>>> graph.block_count
10
>>> bloq.GalleryItem("cnot") is bloq.GalleryItem.CNOT
True

meth bloq.GalleryItem.load

load() → _core.BlockGraph

Build this entry’s block graph.

Returns:

A complete, valid graph for this gallery entry.

Return type:

BlockGraph

Examples

>>> import bloq
>>> bloq.GalleryItem.BELL_STATE.load().port_count
2

meth bloq.GalleryItem.source

source() → str

The .blog source text of this entry.

Examples

>>> import bloq
>>> bloq.GalleryItem.CNOT.source().startswith("BLOG 1.0")
True

attr bloq.GalleryItem.AND_4T

AND_4T = 'and_4t'

attr bloq.GalleryItem.BELL_STATE

BELL_STATE = 'bell_state'

attr bloq.GalleryItem.CCZ_4X3X6

CCZ_4X3X6 = 'ccz_4x3x6'

attr bloq.GalleryItem.CCZ_4X3X7_TELS

CCZ_4X3X7_TELS = 'ccz_4x3x7_tels'

attr bloq.GalleryItem.CCZ_GATE_TELEPORT

CCZ_GATE_TELEPORT = 'ccz_gate_teleport'

attr bloq.GalleryItem.CCZ_INJECTED_AND

CCZ_INJECTED_AND = 'ccz_injected_and'

attr bloq.GalleryItem.CCZ_INJECTED_MAJ

CCZ_INJECTED_MAJ = 'ccz_injected_maj'

attr bloq.GalleryItem.CNOT

CNOT = 'cnot'

attr bloq.GalleryItem.CZ_SPATIAL_H

CZ_SPATIAL_H = 'cz_spatial_h'

attr bloq.GalleryItem.CZ_TEMPORAL_H

CZ_TEMPORAL_H = 'cz_temporal_h'

attr bloq.GalleryItem.GHZ

GHZ = 'ghz'

attr bloq.GalleryItem.GHZ_PATCH_ROTATIONS

GHZ_PATCH_ROTATIONS = 'ghz_patch_rotations'

attr bloq.GalleryItem.GHZ_SLIDE_THEN_GLIDE

GHZ_SLIDE_THEN_GLIDE = 'ghz_slide_then_glide'

attr bloq.GalleryItem.MOVE_ROTATION

MOVE_ROTATION = 'move_rotation'

attr bloq.GalleryItem.ONE_D_YOKED

ONE_D_YOKED = '1d-yoked'

attr bloq.GalleryItem.PHASE_GRADIENT

PHASE_GRADIENT = 'phase_gradient'

attr bloq.GalleryItem.STABILITY

STABILITY = 'stability'

attr bloq.GalleryItem.STEANE_ENCODING

STEANE_ENCODING = 'steane_encoding'

attr bloq.GalleryItem.S_GATE

S_GATE = 's_gate'

attr bloq.GalleryItem.TEN_BIT_ADDER

TEN_BIT_ADDER = 'ten_bit_adder'

attr bloq.GalleryItem.THREE_BIT_ADDER

THREE_BIT_ADDER = 'three_bit_adder'

attr bloq.GalleryItem.THREE_CNOTS

THREE_CNOTS = 'three_cnots'

attr bloq.GalleryItem.THTH

THTH = 'thth'

attr bloq.GalleryItem.TOFFOLI_FROM_AND_DELAYED_CZ

TOFFOLI_FROM_AND_DELAYED_CZ = 'toffoli_from_and_delayed_cz'

attr bloq.GalleryItem.T_COMPARISON

T_COMPARISON = 't_comparison'

attr bloq.GalleryItem.T_GATE

T_GATE = 't_gate'

attr bloq.GalleryItem.T_WITH_PREPARED_Y

T_WITH_PREPARED_Y = 't_with_prepared_y'

attr bloq.GalleryItem.UMA

UMA = 'uma'

attr bloq.GalleryItem.X_MEMORY

X_MEMORY = 'x_memory'

attr bloq.GalleryItem.Y_MEMORY

Y_MEMORY = 'y_memory'

prop bloq.GalleryItem.categories

property categories : tuple[str, ...]

The entry’s categories, for selecting a family of examples.

Examples

>>> import bloq
>>> clifford = [g for g in bloq.GalleryItem if "clifford" in g.categories]
>>> bloq.GalleryItem.CNOT in clifford
True
>>> bloq.GalleryItem.T_GATE in clifford
False

prop bloq.GalleryItem.description

property description : str

The human-readable description of this entry.

Examples

>>> import bloq
>>> "CNOT" in bloq.GalleryItem.CNOT.description
True

prop bloq.GalleryItem.id

property id : str

The gallery id string, as accepted by the CLI and .blog tooling.

Examples

>>> import bloq
>>> bloq.GalleryItem.X_MEMORY.id
'x_memory'

IR programs and graph traversal

Bloq owns the physical program, shared templates, and nested control regions. Loading a text or binary artifact decodes it without a full audit; call validate() when that audit is required. Structural statistics count stored region bodies once, independently of how many attempts execution may take.

Node IDs are local to one graph level. Preserve the owning path in walk results when identifying nested nodes; the same numeric ID can occur in different regions. Accessors return snapshots, including detached SubGraph values, so changing an inspected object does not edit the original program. Use the program’s editing methods for mutations.

class bloq.Bloq

class Bloq

A compiled Bloq IR program: a graph of quantum, classical, and region nodes plus a shared template pool. Produced by compile() or loaded from the .bloqir / .bloq exchange formats.

Read the top graph level with nodes / node / node_ids / edges; nested region bodies hang off their RegionNode payloads. Serialize with to_text / to_binary (or save to a path) and reload with from_text / from_binary (or load), picking the codec by .bloqir (text) or .bloq (binary) extension.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> program
<Bloq nodes=2 edges=1 qubits=17>
>>> len(program.node_ids())
2
>>> program.node(0).is_quantum()
True
>>> program.node(99) is None
True
>>> len(program.edges())
1
>>> bloq.Bloq.from_text(program.to_text()).to_binary() == program.to_binary()
True
>>> bloq.Bloq.from_binary(program.to_binary()).to_binary() == program.to_binary()
True

meth bloq.Bloq.from_binary

static from_binary(data: bytes) → Bloq

Decodes a program from the binary .bloq exchange format.

Parameters:
data: bytes

The binary .bloq artifact bytes to decode.

Raises:

BinaryDecodeError – If the bytes are not a valid .bloq artifact.

meth bloq.Bloq.from_text

static from_text(text: str) → Bloq

Parses a program from the .bloqir text exchange format.

Parameters:
text: str

The .bloqir text-format source to parse.

Raises:

TextParseError – If the text is not a valid .bloqir program.

meth bloq.Bloq.load

static load(path: str | os.PathLike | pathlib.Path) → Bloq

Loads a program from path, picking the codec by extension (.bloqir text, .bloq binary).

Parameters:
path: str | os.PathLike | pathlib.Path

The file path to read; its extension selects the codec.

Raises:

meth bloq.Bloq.classical_value

classical_value(node: int, *, output: ObservableOutput = ObservableOutput.Corrected, pins: bool | None = None, forced_observables: Mapping[int, bool] | None = None) → bool

The Boolean value fixed by the predicate assignment.

Complete observables read their assumed corrected forced_observables values; compute nodes fold their expressions over those values. A decoder flip cannot be inferred from a corrected-value assignment.

Parameters:
node: int

The top-level node id to evaluate.

output: ObservableOutput = ObservableOutput.Corrected

The selected Corrected or Flip port.

pins: bool | None = None

One Boolean value for every predicate leaf.

forced_observables: Mapping[int, bool] | None = None

Observable index to assumed decoded value. Cannot be combined with pins.

Raises:
  • InvalidArgumentError – If both assignment arguments are supplied.

  • BloqError – If the node is missing, is quantum, is a repeat-until-success region, or reaches an unfixed value.

meth bloq.Bloq.data_inputs

data_inputs(id: int) → list[ValueInput]

Boolean and structural composition inputs, excluding activation.

meth bloq.Bloq.detector_bundle

detector_bundle(id: int) → DetectorBundle

A shared detector bundle by pool id.

meth bloq.Bloq.deterministic_emit_order

deterministic_emit_order() → list[int]

The deterministic Kahn topological emit order. Raises BloqError on a cyclic (unvalidated or hand-built) graph.

meth bloq.Bloq.edges

edges() → list[BloqEdgeRef]

Every top-level edge.

meth bloq.Bloq.edges_between

edges_between(from_node: int, to_node: int) → list[BloqEdgeRef]

Every top-level edge from_node -> to_node.

Parameters:
from_node: int

The source node id.

to_node: int

The target node id.

meth bloq.Bloq.emission_plan

emission_plan(node: int, path: collections.abc.Sequence[tuple[int, str]] | None = None, *, noise: float | None = None) → EmissionPlan

The node’s merged circuit plus the instance-space id maps — the per-node unit a custom backend emits. See EmissionPlan.

A minimal gate-counting backend over a program with no region nodes:

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> gates = 0
>>> for node_id in program.deterministic_emit_order():
...     plan = program.emission_plan(node_id)
...     for body in range(plan.circuit.body_count):
...         gates += sum(isinstance(op, bloq.ir.CircuitOp.Gate)
...                      for op in plan.circuit.ops(body))
>>> gates > 0
True

deterministic_emit_order() lists only the top level, so this loop covers a program with no region nodes. A backend that must handle control flow walks every level instead — iterate walk() (or levels()) and pass each node’s path — because region bodies hold quantum nodes this top-level loop never reaches.

Parameters:
node: int

The node’s level-local id.

path: collections.abc.Sequence[tuple[int, str]] | None = None

The node’s graph level as (owner_node_id, body_selector) hops from the top level (a WalkNode.path). None or empty for a top-level node.

noise: float | None = None

Uniform circuit-level noise probability in [0, 1]. None (the default) leaves the circuit noiseless. Noise is materialized after instance merging. When a moment crosses a repeat boundary, use plan.normalized_template(id) or program.template(id) for the returned plan’s side tables.

Raises:
  • InvalidArgumentError – If noise is invalid, path names a missing region or body, or node is not at that level.

  • BloqError – If the node’s instances do not merge.

meth bloq.Bloq.flatten

flatten() → None

Flattens every REPEAT block in the program: each looped template is unrolled into a straight-line circuit, repeat-scoped detectors expand into one concrete detector per unrolled iteration (seeded and advanced by the loop-carried recurrence, matching Stim emission semantics), and all loop-carried detector state is cleared. Flattened templates are appended to the pool and instances re-pointed; instance-space references stay valid because each measurement’s final unrolled occurrence keeps its original id.

Verify-before-apply — a failed flatten leaves the program untouched. Inserting memory rounds afterwards splices looped padding templates again; flatten again if needed.

Raises:

BloqError – If a parity references an undefined loop state, an instance references a missing template.

meth bloq.Bloq.has_conditional_membership

has_conditional_membership() → bool

Whether guarded quantum stages, seams, or activated quantum regions need membership selection. Classical activation alone does not require pinning.

meth bloq.Bloq.has_path

has_path(from_node: int, to_node: int) → bool

Whether a directed top-level path from_node -> to_node exists.

Parameters:
from_node: int

The start node id.

to_node: int

The destination node id.

meth bloq.Bloq.incoming

incoming(id: int) → list[BloqEdgeRef]

The top-level edges into id. Empty for a stale id.

Parameters:
id: int

The top-level node whose incoming edges to return.

meth bloq.Bloq.insert_memory_rounds

insert_memory_rounds(from_node: int, to_node: int, rounds: int, *, path: collections.abc.Sequence[tuple[int, str]] | None = None) → int

Splices memory-round padding into the Quantum edge from_node -> to_node at path, waiting rounds rounds.

Self-contained: the padding templates come from the program’s recorded edge-owned padding provenance (stamped at compile time), so a program loaded from a .bloq needs neither the source graph nor a recompile. Node ids held across this call must be re-resolved (id recycling).

Parameters:
from_node: int

The source node id of the Quantum edge to splice into.

to_node: int

The target node id of that Quantum edge.

rounds: int

The number of syndrome-extraction rounds the padding waits.

path: collections.abc.Sequence[tuple[int, str]] | None = None

Optional (region_id, body_selector) hops. Omit for a top-level edge.

Returns:

The id of the newly spliced padding node.

Raises:

BloqError – If the seam carries no padding provenance (hand-built program, or one compiled before provenance recording) or the splice fails.

meth bloq.Bloq.insert_memory_rounds_after

insert_memory_rounds_after(node: int, rounds: int, *, path: collections.abc.Sequence[tuple[int, str]]) → int

Appends physical memory rounds after a terminal quantum node inside a region body. Existing ordering consumers and cross-region detectors are moved to the inserted padding node.

Parameters:
node: int

Terminal quantum node id within path.

rounds: int

Number of syndrome-extraction rounds to append.

path: collections.abc.Sequence[tuple[int, str]]

(region_id, body_selector) hops to the node’s graph level.

Returns:

The inserted padding node’s level-local id.

meth bloq.Bloq.insert_memory_rounds_batch

insert_memory_rounds_batch(targets: collections.abc.Sequence[MemoryRoundTarget], rounds: int) → list[int]

Inserts memory rounds at all targets atomically.

Targets may mix MemoryRoundTarget.Edge and MemoryRoundTarget.After at different graph levels. Returns inserted node ids in target order; each id belongs to its target’s graph level. An empty list is a no-op. Any error leaves the entire program unchanged.

Parameters:
targets: collections.abc.Sequence[MemoryRoundTarget]

Edge or terminal-region targets, located before the edit.

rounds: int

Number of memory rounds at every target; must be at least 1.

Raises:
  • InvalidArgumentError – If a target path cannot be resolved.

  • BloqError – If membership is unresolved, a target or seam is invalid, or rounds is zero.

meth bloq.Bloq.level_at

level_at(path: collections.abc.Sequence[tuple[int, str]]) → SubGraph

The one graph level path names, as an owned snapshot.

path is the (owner_node_id, body_selector) chain levels() and WalkNode.path hand out; an empty path is the top level. This is the targeted read that levels() is the exhaustive one of — reach for it instead of scanning levels() for a known path, which snapshots every level to keep one.

Parameters:
path: collections.abc.Sequence[tuple[int, str]]

The (owner_id, selector) hops to the level, outermost first.

Raises:

InvalidArgumentError – If a hop names a missing node, a non-region node, or a body selector the region does not have.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> rus = program.regions_of(bloq.ir.RegionKind.RepeatUntilSuccess)[0]
>>> program.level_at(rus.path + [(rus.node, "body")]).node_count
5
>>> program.level_at([]).node_ids() == program.node_ids()
True

meth bloq.Bloq.levels

levels() → list[tuple[list[tuple[int, str]], SubGraph]]

Every graph level as (path, level), pre-order top-down: the top level first (empty path), then each region body.

path is the (owner_node_id, body_selector) chain to the level and level is an owned SubGraph snapshot. Use this for whole-program table passes that read a level as a unit — instance collection, id allocation, per-level edge queries — rather than reacting to individual nodes (that is walk()).

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> levels = program.levels()
>>> path, top = levels[0]
>>> path
[]
>>> top.node_ids() == program.node_ids()
True
>>> top.node_count == program.node_count
True

A per-level table pass. Summing each level’s node count reaches every nested node, so the total matches the full walk():

>>> sum(level.node_count for _path, level in levels) == len(program.walk())
True

Nested levels carry a non-empty path naming their owner region and body selector:

>>> len(levels) > 1
True
>>> nested_paths = [path for path, _level in levels if path]
>>> all(
...     selector == "body"
...     for path in nested_paths
...     for _owner, selector in path
... )
True

meth bloq.Bloq.logical_outputs

logical_outputs() → list[LogicalOutput]

Complete terminal logical X/Z operators used by execution hooks.

meth bloq.Bloq.node

node(id: int) → BloqNode | None

The top-level node at id, or None when the id is stale.

Parameters:
id: int

The top-level node id to look up.

meth bloq.Bloq.node_by_block

node_by_block(pos: tuple[int, int, int]) → int | None

The top-level node fused from the source block at pos, or None.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) source-graph block position.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> program.node_by_block((0, 0, 0)) is not None
True

meth bloq.Bloq.node_ids

node_ids() → list[int]

Every top-level node id, in ascending id order.

meth bloq.Bloq.node_measurement_count

node_measurement_count(id: int) → int

The static measurement-site count under id; all region bodies count.

Parameters:
id: int

The node id whose measurement count to return.

Raises:

InvalidArgumentError – If no node has the given id (stale id).

meth bloq.Bloq.node_qubits

node_qubits(id: int) → list[tuple[int, int]]

The layout qubits the node at id occupies, sorted by (x, y).

Parameters:
id: int

The node id whose layout qubits to return.

Raises:

InvalidArgumentError – If no node has the given id (stale id), or translating a template qubit by its instance offset exceeds the 32-bit coordinate range.

meth bloq.Bloq.nodes

nodes() → list[tuple[int, BloqNode]]

Every top-level (id, node), in ascending id order.

meth bloq.Bloq.open_value_producers

open_value_producers() → list[int]

Top-level value producers with no local consumer; independent of declared outputs.

meth bloq.Bloq.outgoing

outgoing(id: int) → list[BloqEdgeRef]

The top-level edges out of id. Empty for a stale id.

Parameters:
id: int

The top-level node whose outgoing edges to return.

meth bloq.Bloq.output_frames

output_frames() → list[FramePair]

Per-output terminal Pauli-frame signs, ordered by source output port.

meth bloq.Bloq.pin_membership

pin_membership(choices: Mapping[str, bool]) → Bloq

Return a selected copy for named structural branches and selective measurements. Keys are NodeProvenance.BranchSelector.name values; every selector must be pinned consistently. Guards implied by the pins are removed. The original program stays unchanged, and RUS regions retain their runtime semantics.

Raises:

BloqError – If pins are missing, unknown, inconsistent, or the program is invalid.

meth bloq.Bloq.pipe_padding

pipe_padding() → list[PipePadding]

A flattened view of the edge-owned memory-padding provenance. Inspect BloqEdge.Quantum.padding when the owning seam matters.

meth bloq.Bloq.quantum_input

quantum_input(node: int) → int

The single top-level quantum node feeding node.

Parameters:
node: int

The consumer node id.

Raises:

BloqError – If the node has zero or several quantum inputs.

meth bloq.Bloq.quantum_nodes

quantum_nodes() → list[tuple[int, QuantumNode]]

The top level’s (id, quantum_node) pairs in ascending id order, skipping classical and region nodes. See the SubGraph twin for why this is not the emit order.

meth bloq.Bloq.quantum_tail

quantum_tail() → int

The unique top-level quantum node with no outgoing quantum edge. Classical consumers do not disqualify it.

Raises:

BloqError – If the level has zero or several such nodes.

meth bloq.Bloq.regions_of

regions_of(kind: RegionKind) → list[RegionRef]

Every region of kind, at every nesting level, in level order.

Parameters:
kind: RegionKind

The RegionKind to filter by.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> len(program.regions_of(bloq.ir.RegionKind.RepeatUntilSuccess))
1

meth bloq.Bloq.resolve_classical

resolve_classical(node: int, *, output: ObservableOutput = ObservableOutput.Corrected, pins: bool | None = None, forced_observables: Mapping[int, bool] | None = None) → ClassicalResolution

Resolves classical dataflow to its measurement parity, constant sign, and decoder observable under a fixed predicate assignment.

Parameters:
node: int

The top-level classical node id to resolve.

output: ObservableOutput = ObservableOutput.Corrected

The selected Corrected or Flip port.

pins: bool | None = None

One Boolean value for every predicate leaf.

forced_observables: Mapping[int, bool] | None = None

Observable index to assumed decoded value. Cannot be combined with pins.

Raises:
  • InvalidArgumentError – If both assignment arguments are supplied.

  • BloqError – If the node is missing, is not classical, or its dataflow cannot be resolved.

meth bloq.Bloq.save

save(path: str | os.PathLike | pathlib.Path) → None

Saves the program to path, picking the codec by extension (.bloqir text, .bloq binary).

Parameters:
path: str | os.PathLike | pathlib.Path

The destination file path; its extension selects the codec.

Raises:
  • InvalidArgumentError – If the extension is neither .bloqir nor .bloq.

  • OSError – If the file cannot be written.

Examples

>>> import bloq, tempfile, os
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> directory = tempfile.mkdtemp()
>>> for name in ("prog.bloqir", "prog.bloq"):
...     path = os.path.join(directory, name)
...     program.save(path)
...     bloq.Bloq.load(path).to_binary() == program.to_binary()
True
True

meth bloq.Bloq.selection_seams

selection_seams() → list[tuple[int, int]]

The (source, selection) quantum edges feeding top-level guarded quantum selections, in ascending target- then source-node order.

Use these seams as targets for insert_memory_rounds_batch.

Raises:

BloqError – If a selection has no quantum input edge.

meth bloq.Bloq.set_template_repetitions

set_template_repetitions(template: int, repetitions: int) → None

Retunes how many times a template’s REPEAT body runs.

Templates are pooled, so this changes every instance of the template. repetitions is the loop’s repeat count, not a round count — the template’s straight-line prologue still runs once on top of it.

Parameters:
template: int

The template pool id.

repetitions: int

The new REPEAT count.

Raises:

BloqError – If the id is not in the pool, or the template does not have exactly one repeat loop.

meth bloq.Bloq.sorted_layout_coords

sorted_layout_coords() → list[tuple[int, int]]

The layout qubit coordinates, sorted by (x, y).

Raises:

InvalidArgumentError – If translating a template qubit by its instance offset exceeds the 32-bit coordinate range.

meth bloq.Bloq.stable_key_map

stable_key_map() → dict[NodeKey, int]

Top-level nodes with a compile-stable identity, keyed by that identity.

Use it to carry node references between two compiles of one graph — a program and its compile_clifford_proxy, say — where ids need not agree but keys do.

Raises:

BloqError – If two nodes share a key, or the graph is cyclic.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> sorted(program.stable_key_map().values())
[0, 2]

meth bloq.Bloq.stats

stats() → BloqStats

Structural IR inventory across every graph level, without flattening.

Counts include every concrete node/edge type and the compiled template pool. Each stored region body contributes once. Static means no retry regions, node activation, quantum membership guards, guarded seams, or shot discard. Ordinary classical readout/decoder computation and fixed circuit repeats remain static. This does not certify validity or backend emittability. Physical qubits, gates, and measurements are not counted.

Returns:

Read-only structural counts; print(program.stats())

prints a tree summary.

Return type:

BloqStats

Raises:

InvalidArgumentError – If a structural count overflows.

meth bloq.Bloq.subdivide_quantum_edge

subdivide_quantum_edge(from_node: int, to_node: int, padding: collections.abc.Sequence[tuple[int, tuple[int, int]]], rounds: int) → int

Lower-level splice for callers that already hold padding template ids. Verify-before-apply — a failed splice leaves the program untouched.

Parameters:
from_node: int

The source node id of the Quantum edge to splice into.

to_node: int

The target node id of that Quantum edge.

padding: collections.abc.Sequence[tuple[int, tuple[int, int]]]

The padding instances to insert, each a (template_id, (offset_x, offset_y)) pair.

rounds: int

The number of syndrome-extraction rounds the padding waits.

Returns:

The id of the newly spliced padding node.

Raises:

BloqError – If the splice fails (any EditError).

meth bloq.Bloq.template

template(id: int) → Template

The template with the given pool id. Ids run 0..template_count and are stable for the program’s life.

Parameters:
id: int

The template pool id (e.g. TemplateInstance.template_id).

Raises:

InvalidArgumentError – If id is not in the pool.

meth bloq.Bloq.to_binary

to_binary() → bytes

Encodes the program as a binary .bloq artifact.

meth bloq.Bloq.to_svg

to_svg(*, include_classical: bool = True) → str

Renders the nested IR dependency graph as a self-contained SVG.

Quantum stages and region bodies are always shown. Set include_classical=False to hide classical nodes and their edges. This is a structural view, not a physical circuit or timing diagram.

meth bloq.Bloq.to_text

to_text() → str

Renders the program in the .bloqir text exchange format.

meth bloq.Bloq.validate

validate() → None

Checks the program against the IR’s well-formedness rules. Raises BloqValidationError with the violated rule in the message.

meth bloq.Bloq.value_consumers

value_consumers(id: int) → list[tuple[int, int]]

The consumers of id’s Boolean outputs, as (consumer, slot).

Parameters:
id: int

The producer node id whose Value consumers to return.

meth bloq.Bloq.value_inputs

value_inputs(id: int) → list[ValueInput]

The producers wired into id’s Value slots.

Parameters:
id: int

The consumer node id whose Value inputs to return.

meth bloq.Bloq.walk

walk() → list[WalkNode]

Every node at every nesting level, as WalkNode snapshots in pre-order depth-first order: a level’s nodes in ascending id order, descending into each region node’s bodies before moving on.

This is the whole-program counterpart to nodes() (top level only). It eagerly visits every node, including those in region bodies; there is no pruning or early exit — filter or slice the returned list yourself. The ordering is the deterministic scan order (ascending id per level), not the execution schedule; use deterministic_emit_order() per level for that.

Each WalkNode carries the node’s path (the (owner_id, selector) hops to its level, empty at the top level), its level-local id, and an owned node snapshot. Dispatch on what a node computes with isinstance over w.node.kind (BloqNodeKind.Quantum / Classical / Region).

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> walk = program.walk()

The top-level nodes come out first, in node-id order; the walk then descends into region bodies, so it visits more than the top level:

>>> [w.id for w in walk if not w.path] == program.node_ids()
True
>>> len(walk) > program.node_count
True

Dispatch on what each node computes. The magic-state (T) program lowers to nested control-flow regions, so the walk sees region nodes:

>>> tally = {"quantum": 0, "classical": 0, "region": 0}
>>> for w in walk:
...     kind = w.node.kind
...     if isinstance(kind, bloq.ir.BloqNodeKind.Quantum):
...         tally["quantum"] += 1
...     elif isinstance(kind, bloq.ir.BloqNodeKind.Classical):
...         tally["classical"] += 1
...     elif isinstance(kind, bloq.ir.BloqNodeKind.Region):
...         tally["region"] += 1
>>> sum(tally.values()) == len(walk)
True
>>> tally["region"] > 0
True

A node inside a region body has a non-empty path; its top_level_ancestor() is the outermost enclosing region’s id — and because ids are level-local, that is the only piece of a nested node’s id/path that is a valid top-level node() lookup key:

>>> nested = next(w for w in walk if w.path)
>>> nested.path[0][1] == "body"
True
>>> program.node(nested.top_level_ancestor()).is_region()
True

attr bloq.Bloq.boundary_outputs

boundary_outputs

Declared Observable or region ids exporting boundary bindings.

attr bloq.Bloq.detector_bundle_count

detector_bundle_count

Number of shared detector bundles in the program pool.

attr bloq.Bloq.edge_count

edge_count

The number of top-level edges. Use stats() for all levels.

attr bloq.Bloq.measurement_count

measurement_count

The number of static measurement sites. Both branch arms count.

attr bloq.Bloq.metadata

metadata

Namespaced producer metadata. Values are Python int or str scalars.

attr bloq.Bloq.node_count

node_count

The number of top-level nodes. Use stats() for all levels.

attr bloq.Bloq.quantum_node_count

quantum_node_count

The number of top-level quantum nodes (excludes classical/region).

attr bloq.Bloq.qubit_count

qubit_count

The number of distinct layout qubits the program touches.

Raises:

InvalidArgumentError – If translating a template qubit by its instance offset exceeds the 32-bit coordinate range.

attr bloq.Bloq.template_count

template_count

The number of templates in the program’s shared pool.

attr bloq.Bloq.value_output

value_output

The declared Boolean source, or None for constant false.

class bloq.ir.BloqStats

class BloqStats

Structural counts over every level of stored Bloq IR, returned by Bloq.stats. Physical circuit payloads and runtime executions are not counted.

attr bloq.ir.BloqStats.edge_count

edge_count

Edges at every graph level.

attr bloq.ir.BloqStats.edge_counts

edge_counts

Edge counts by Quantum, Value, and Order, including zero-count types.

attr bloq.ir.BloqStats.is_static

is_static

no retry regions, node activation, membership guards, guarded seams, or Discard. Ordinary classical readout/decoder computation and fixed circuit repeats remain static. This does not certify validity or backend emittability.

Type:

Fixed IR execution structure

attr bloq.ir.BloqStats.node_count

node_count

Nodes at every graph level, including region containers.

attr bloq.ir.BloqStats.node_counts

node_counts

Node counts by concrete variant, including zero-count types.

attr bloq.ir.BloqStats.template_count

template_count

Templates in the compiled pool, including unreferenced templates.

class bloq.ir.SubGraph

class SubGraph

A nested region body: a graph level with the same read accessors as the top level. Snapshot semantics — this is an owned copy, detached from the program it was read from.

meth bloq.ir.SubGraph.data_inputs

data_inputs(id: int) → list[ValueInput]

Boolean and structural composition inputs, excluding activation.

meth bloq.ir.SubGraph.deterministic_emit_order

deterministic_emit_order() → list[int]

The level’s deterministic Kahn topological order. Raises BloqError on a cyclic graph.

meth bloq.ir.SubGraph.edges

edges() → list[BloqEdgeRef]

Every edge at this level.

meth bloq.ir.SubGraph.edges_between

edges_between(from_node: int, to_node: int) → list[BloqEdgeRef]

Every edge from_node -> to_node (parallel edges are legal).

Parameters:
from_node: int

The source node id.

to_node: int

The target node id.

meth bloq.ir.SubGraph.has_path

has_path(from_node: int, to_node: int) → bool

Whether a directed path from_node -> to_node exists (any edge kind).

Parameters:
from_node: int

The start node id.

to_node: int

The destination node id.

meth bloq.ir.SubGraph.incoming

incoming(id: int) → list[BloqEdgeRef]

The edges into id. Empty for a stale id.

Parameters:
id: int

The node whose incoming edges to return.

meth bloq.ir.SubGraph.node

node(id: int) → BloqNode | None

The node at id, or None when the id is stale.

Parameters:
id: int

The node id to look up at this level.

meth bloq.ir.SubGraph.node_ids

node_ids() → list[int]

Every node id at this level, in ascending id order.

meth bloq.ir.SubGraph.nodes

nodes() → list[tuple[int, BloqNode]]

Every (id, node) at this level, in ascending id order.

meth bloq.ir.SubGraph.open_value_producers

open_value_producers() → list[int]

Value producers with no local consumer; independent of declared outputs.

meth bloq.ir.SubGraph.outgoing

outgoing(id: int) → list[BloqEdgeRef]

The edges out of id. Empty for a stale id.

Parameters:
id: int

The node whose outgoing edges to return.

meth bloq.ir.SubGraph.quantum_input

quantum_input(node: int) → int

The single quantum node at this level feeding node.

Parameters:
node: int

The consumer node id.

Raises:

BloqError – If the node has zero or several quantum inputs.

meth bloq.ir.SubGraph.quantum_nodes

quantum_nodes() → list[tuple[int, QuantumNode]]

This level’s (id, quantum_node) pairs in ascending id order (like nodes()), skipping classical and region nodes.

Ascending id, not emit order: a caller appending circuit text wants deterministic_emit_order() filtered by is_quantum() instead.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> rus = next(n for _, n in program.nodes() if n.is_region())
>>> len(rus.region.body.quantum_nodes())
2

meth bloq.ir.SubGraph.quantum_tail

quantum_tail() → int

The unique quantum tail at this level: a quantum node with no outgoing quantum edge. Classical consumers do not disqualify it.

Raises:

BloqError – If the level has zero or several such nodes.

meth bloq.ir.SubGraph.stable_keys

stable_keys() → list[tuple[NodeKey, int]]

Every (key, id) at this level, keyed by compile-stable identity.

Raises:

BloqError – If the level is cyclic.

meth bloq.ir.SubGraph.value_consumers

value_consumers(id: int) → list[tuple[int, int]]

The consumers of id’s Boolean outputs, as (consumer, slot).

Parameters:
id: int

The producer node id whose Value consumers to return.

meth bloq.ir.SubGraph.value_inputs

value_inputs(id: int) → list[ValueInput]

The producers wired into id’s Value slots.

Parameters:
id: int

The consumer node id whose Value inputs to return.

attr bloq.ir.SubGraph.boundary_outputs

boundary_outputs

Declared Observable or region ids exporting boundary bindings.

attr bloq.ir.SubGraph.edge_count

edge_count

The number of edges at this level.

attr bloq.ir.SubGraph.node_count

node_count

The number of nodes at this level.

attr bloq.ir.SubGraph.value_output

value_output

The declared Boolean source, or None for constant false.

class bloq.ir.BloqNode

class BloqNode

A graph node: kind is what it computes, provenance is why it exists.

kind is a BloqNodeKind (quantum, classical, or region); the is_quantum / is_classical / is_region predicates dispatch on it without an isinstance check. provenance records the source-level construct the node realizes.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> node = program.node(0)
>>> node.is_quantum(), node.is_classical()
(True, False)

meth bloq.ir.BloqNode.block_members

block_members() → list[tuple[int, int, int]]

The source block positions this node was fused from (empty unless the provenance is BlockComponent).

meth bloq.ir.BloqNode.is_classical

is_classical() → bool

True if the node carries classical dataflow.

meth bloq.ir.BloqNode.is_quantum

is_quantum() → bool

True if the node carries a quantum payload.

meth bloq.ir.BloqNode.is_region

is_region() → bool

True if the node is a control-flow region.

meth bloq.ir.BloqNode.memory_rounds

memory_rounds() → int | None

The spliced node’s wait duration in whole syndrome-extraction rounds, or None for anything other than memory padding.

attr bloq.ir.BloqNode.activation

activation

Optional activation Value slot. A false activation skips this value or region.

attr bloq.ir.BloqNode.classical

classical

The node’s classical payload, or None for a quantum or region node.

attr bloq.ir.BloqNode.kind

kind

What the node computes (quantum, classical, or region).

attr bloq.ir.BloqNode.provenance

provenance

Why the node exists — its source-level origin.

attr bloq.ir.BloqNode.quantum

quantum

The node’s quantum payload, or None for a classical or region node.

The unwrapping twin of is_quantum(): reaching a payload through kind otherwise costs an isinstance narrowing plus an attribute whose name differs by variant.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> len(program.node(0).quantum.instances)
1
>>> program.node(0).region is None
True

attr bloq.ir.BloqNode.region

region

The node’s region payload, or None for a quantum or classical node.

Pair with RegionNode.kind to select one region variant in a single test:

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> bodies = [
...     node.region.body
...     for _, node in program.nodes()
...     if node.region is not None
...     and node.region.kind is bloq.ir.RegionKind.RepeatUntilSuccess
... ]
>>> len(bodies)
1

attr bloq.ir.BloqNode.stable_key

stable_key

The node’s compile-stable identity, or None for a provenance that carries none. Computed when the snapshot is taken, because the snapshot does not keep the node it was taken from.

class bloq.ir.BloqNodeKind

class BloqNodeKind

What a BloqNode computes: a quantum payload, classical dataflow, or a control-flow region. Read from BloqNode.kind and dispatch with isinstance (BloqNodeKind.Quantum / Classical / Region); each variant carries its payload. The BloqNode predicates is_quantum() / is_classical() / is_region() test the variant without an isinstance check.

class bloq.ir.BloqNodeKind.Classical

class Classical(node)

attr bloq.ir.BloqNodeKind.Classical.node

node

class bloq.ir.BloqNodeKind.Quantum

class Quantum(node)

attr bloq.ir.BloqNodeKind.Quantum.node

node

class bloq.ir.BloqNodeKind.Region

class Region(region)

attr bloq.ir.BloqNodeKind.Region.region

region

class bloq.ir.BloqEdge

class BloqEdge

A graph edge payload: a quantum face seam, a classical-bit dataflow dependency, or a payload-free ordering constraint.

class bloq.ir.BloqEdge.Compose

class Compose(slot, role)

Structural recipe composition, including raw parity and boundary bindings.

attr bloq.ir.BloqEdge.Compose.role

role

attr bloq.ir.BloqEdge.Compose.slot

slot

class bloq.ir.BloqEdge.Order

class Order

Pure sequencing, no data.

class bloq.ir.BloqEdge.Quantum

class Quantum(pipes, guard)

A quantum face seam: its temporal pipes, each with its edge-owned decoder-wait padding provenance.

attr bloq.ir.BloqEdge.Quantum.guard

guard

attr bloq.ir.BloqEdge.Quantum.pipes

pipes

class bloq.ir.BloqEdge.Value

class Value(slot, role, output)

A classical-bit dependency feeding the consumer’s slot-th input.

attr bloq.ir.BloqEdge.Value.output

output

attr bloq.ir.BloqEdge.Value.role

role

attr bloq.ir.BloqEdge.Value.slot

slot

class bloq.ir.BloqEdgeRef

class BloqEdgeRef

One graph edge with its endpoint node ids — the element type of Bloq.edges(), incoming(), outgoing(), and edges_between() (and their SubGraph twins). source and target are level-local node ids; edge is the BloqEdge payload (dispatch on its variant with isinstance).

meth bloq.ir.BloqEdgeRef.is_compose

is_compose() → bool

True if this structurally composes an observable recipe.

meth bloq.ir.BloqEdgeRef.is_order

is_order() → bool

True if this is a payload-free ordering constraint.

meth bloq.ir.BloqEdgeRef.is_quantum

is_quantum() → bool

True if this is a quantum face seam.

Filtering an edge list by payload variant is the common read; the predicates spell it without an isinstance on edge.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> [e.source for e in program.incoming(3) if e.is_quantum()]
[2]

meth bloq.ir.BloqEdgeRef.is_value

is_value() → bool

True if this is a classical-bit dataflow dependency.

attr bloq.ir.BloqEdgeRef.edge

edge

The edge payload.

attr bloq.ir.BloqEdgeRef.source

source

The source node id.

attr bloq.ir.BloqEdgeRef.target

target

The target node id.

class bloq.ir.WalkNode

class WalkNode

One node visited by Bloq.walk(): its owner path, its level-local id, and an owned snapshot of the node itself.

A node id is only unique within its graph level, so id alone does not address a node inside a region body. The path — the chain of (owner_node_id, body_selector) hops from the top level down to this node’s level, outermost first — is the missing half of a program-unique address. Each hop is a 2-tuple (owner_id, selector) where selector is "body"; path is empty for a top-level node.

Getters:
  • path: the (owner_id, selector) hops to this node’s level.

  • id: the node’s level-local id.

  • node: an owned BloqNode snapshot (dispatch on node.kind).

Method top_level_ancestor() returns the outermost enclosing region’s id for a nested node, else the node’s own id. Because ids are level-local, it is the only piece of a nested node’s id/path that keys a top-level Bloq.node() lookup.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> walk = program.walk()

The first visited node is the first top-level node — empty path, and top_level_ancestor() is just its own id:

>>> top = walk[0]
>>> top.path
[]
>>> top.id
0
>>> top.top_level_ancestor()
0

A node inside a region body carries a non-empty path; its top_level_ancestor() resolves to the enclosing region at the top level, which Bloq.node() can look up (a body-local id cannot):

>>> nested = next(w for w in walk if w.path)
>>> owner_id, selector = nested.path[0]
>>> selector == "body"
True
>>> nested.top_level_ancestor() == owner_id
True
>>> program.node(nested.top_level_ancestor()).is_region()
True

meth bloq.ir.WalkNode.top_level_ancestor

top_level_ancestor() → int

The top-level ancestor node id: the outermost enclosing region’s id for a node inside a region body, else this node’s own id.

Because ids are level-local, this is the only piece of id/path that is a valid top-level Bloq.node() lookup key.

attr bloq.ir.WalkNode.id

id

The node’s level-local id (unique only within its level).

attr bloq.ir.WalkNode.node

node

An owned snapshot of the visited node.

attr bloq.ir.WalkNode.path

path

The (owner_node_id, body_selector) hops from the top level down to this node’s level, outermost first. Empty for a top-level node; the selector is "body".

class bloq.ir.NodeKey

class NodeKey

A compile-stable node identity.

Two programs compiled from the same block graph — including a compile_clifford_proxy of it — give corresponding nodes equal keys, even though their BloqNodeId`s need not match. That makes a key the right thing to carry across compiles, and the right thing to use as a `dict key; Bloq.stable_key_map() turns keys back into ids for one program.

Opaque by design: compare, hash, and print them, but do not parse str().

Examples

>>> import bloq
>>> graph = bloq.GalleryItem.X_MEMORY.load()
>>> keys = bloq.compile(graph, distance=3).stable_key_map()
>>> proxy = bloq.compile_clifford_proxy(graph, [], distance=3).stable_key_map()
>>> set(keys) & set(proxy) != set()
True

attr bloq.ir.NodeKey.ordinal

ordinal

Tie-break index among nodes that would otherwise share a key, assigned in deterministic emit order. 0 unless the program has such a clash.

Quantum circuits and templates

A Template stores a reusable physical circuit; a TemplateInstance gives it a program-wide identity and layout offset. A QuantumNode groups placed instances, detectors, and restart syndromes. Template-local coordinates and measurement indices acquire their instance meaning only after placement.

QuantumGuard selects conditional membership. TemporalPipe and PipeSeam describe the quantum connection between stages, including recorded memory padding. Custom backends must account for guards and seams as well as the operations in each template.

class bloq.ir.Circuit

class Circuit

A physical circuit in qubit-coordinate space: the entry body plus any repeat bodies referenced by CircuitOp.Repeat, and a measurement registry giving every measurement a stable id independent of qubit order.

Read-only snapshot; only the compiler constructs circuits.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> circuit = program.template(0).circuit
>>> circuit.num_qubits == len(circuit.qubits())
True
>>> all(record_id < circuit.num_measurements
...     for record_id, _qubit in circuit.measurement_records())
True

meth bloq.ir.Circuit.expanded_measurement_columns

expanded_measurement_columns() → ExpandedMeasurementColumns

Where each measurement id lands once every REPEAT block is unrolled.

A measurement inside a repeat body occupies one column per iteration; the reported column is its last occurrence, which is the one a rec[-k] lookback taken after the loop refers to.

Raises:

InvalidArgumentError – If the circuit references an unknown measurement id or body, or the unrolled column count overflows.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> node = program.deterministic_emit_order()[0]
>>> columns = program.emission_plan(node).circuit.expanded_measurement_columns()
>>> columns.count >= len(columns)
True

meth bloq.ir.Circuit.measurement_records

measurement_records() → list[tuple[int, tuple[int, int]]]

Every (measurement_id, qubit) record, sorted by id.

meth bloq.ir.Circuit.ops

ops(body: int | None = None) → list[CircuitOp]

The ops of one body, in program order. Defaults to the entry body; pass a CircuitOp.Repeat’s body id to read a repeat body.

Raises:

InvalidArgumentError – If body is not an allocated body id.

meth bloq.ir.Circuit.qubits

qubits() → list[tuple[int, int]]

Every qubit coordinate touched by any body or measurement record, sorted.

attr bloq.ir.Circuit.body_count

body_count

The number of circuit bodies, including repeat bodies.

attr bloq.ir.Circuit.entry_body

entry_body

The id of the top-level (entry) body.

attr bloq.ir.Circuit.num_measurements

num_measurements

The number of measurement records in the circuit.

attr bloq.ir.Circuit.num_qubits

num_qubits

The number of distinct qubit coordinates in the circuit.

class bloq.ir.CircuitOp

class CircuitOp

One operation of a Circuit body. Dispatch with isinstance over the variant classes (CircuitOp.Gate, CircuitOp.Measure, CircuitOp.Mpp, CircuitOp.Tick, CircuitOp.Repeat, CircuitOp.ConditionalPauli). Noise operations use CircuitOp.Depolarize1, CircuitOp.Depolarize2, and CircuitOp.PauliError.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> ops = program.template(0).circuit.ops()
>>> isinstance(ops[0], (bloq.ir.CircuitOp.Gate, bloq.ir.CircuitOp.Measure,
...                     bloq.ir.CircuitOp.Mpp, bloq.ir.CircuitOp.Tick,
...                     bloq.ir.CircuitOp.Repeat, bloq.ir.CircuitOp.ConditionalPauli,
...                     bloq.ir.CircuitOp.Depolarize1, bloq.ir.CircuitOp.Depolarize2,
...                     bloq.ir.CircuitOp.PauliError))
True

class bloq.ir.CircuitOp.ConditionalPauli

class ConditionalPauli(corrections)

Physically applied Pauli feedforward: each correction applies its Pauli to its target iff its control bit is 1.

attr bloq.ir.CircuitOp.ConditionalPauli.corrections

corrections

class bloq.ir.CircuitOp.Depolarize1

class Depolarize1(probability, qubits)

Single-qubit depolarizing noise on each target.

attr bloq.ir.CircuitOp.Depolarize1.probability

probability

attr bloq.ir.CircuitOp.Depolarize1.qubits

qubits

class bloq.ir.CircuitOp.Depolarize2

class Depolarize2(probability, qubits)

Two-qubit depolarizing noise on consecutive target pairs.

attr bloq.ir.CircuitOp.Depolarize2.probability

probability

attr bloq.ir.CircuitOp.Depolarize2.qubits

qubits

class bloq.ir.CircuitOp.Gate

class Gate(gate, qubits)

A gate applied to its target qubits (pairwise for two-qubit gates). gate is the Stim-style gate name (e.g. "H", "CX", "R").

attr bloq.ir.CircuitOp.Gate.gate

gate

attr bloq.ir.CircuitOp.Gate.qubits

qubits

class bloq.ir.CircuitOp.Measure

class Measure(basis, qubits, measurements, flip_probability)

A single-qubit measurement of each qubit in basis; measurements[i] is the record id produced for qubits[i].

attr bloq.ir.CircuitOp.Measure.basis

basis

attr bloq.ir.CircuitOp.Measure.flip_probability

flip_probability

attr bloq.ir.CircuitOp.Measure.measurements

measurements

attr bloq.ir.CircuitOp.Measure.qubits

qubits

class bloq.ir.CircuitOp.Mpp

class Mpp(products, measurements)

A multi-Pauli-product measurement (Stim MPP): products[i] is one jointly measured Pauli-product group as (qubit, pauli) pairs, and produces record measurements[i].

attr bloq.ir.CircuitOp.Mpp.measurements

measurements

attr bloq.ir.CircuitOp.Mpp.products

products

class bloq.ir.CircuitOp.PauliError

class PauliError(probability, pauli, qubits)

A fixed-axis Pauli error on each target.

attr bloq.ir.CircuitOp.PauliError.pauli

pauli

attr bloq.ir.CircuitOp.PauliError.probability

probability

attr bloq.ir.CircuitOp.PauliError.qubits

qubits

class bloq.ir.CircuitOp.Repeat

class Repeat(body, repetitions)

Executes body body repetitions times (Stim REPEAT).

attr bloq.ir.CircuitOp.Repeat.body

body

attr bloq.ir.CircuitOp.Repeat.repetitions

repetitions

class bloq.ir.CircuitOp.Tick

class Tick

A moment barrier separating parallel operations.

class bloq.ir.ConditionalCorrection

class ConditionalCorrection

One feedforward correction inside a CircuitOp.ConditionalPauli: apply pauli to target iff the control bit is 1.

attr bloq.ir.ConditionalCorrection.control

control

The measurement id whose outcome gates the correction.

attr bloq.ir.ConditionalCorrection.pauli

pauli

The Pauli axis to apply.

attr bloq.ir.ConditionalCorrection.target

target

The qubit coordinate the correction targets.

class bloq.ir.ExpandedMeasurementColumns

class ExpandedMeasurementColumns

Post-unroll measurement columns of one circuit, from Circuit.expanded_measurement_columns().

Behaves like a read-only mapping from measurement id to column: len(), in, [], and dict(...) all work. count is the total number of columns the unrolled circuit produces, which is larger than len() whenever a measurement repeats.

meth bloq.ir.ExpandedMeasurementColumns.as_dict

as_dict() → dict[int, int]

Every measurement id -> column pair.

meth bloq.ir.ExpandedMeasurementColumns.column

column(measurement: int) → int | None

The column of measurement, or None if the circuit has no such measurement.

Parameters:
measurement: int

The pre-unroll measurement id.

attr bloq.ir.ExpandedMeasurementColumns.count

count

The total number of measurement columns after unrolling.

class bloq.ir.Template

class Template

A reusable circuit template plus its template-local side tables. Pooled and shared by template id; a TemplateInstance places one at a layout offset.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.CNOT.load(), distance=3)
>>> template = program.template(0)
>>> len(template.qubits()) > 0
True
>>> all(m < template.circuit.num_measurements
...     for d in template.detectors for m in d.parity.measurements)
True

meth bloq.ir.Template.qubits

qubits() → list[tuple[int, int]]

The template circuit’s qubit coordinates, sorted.

attr bloq.ir.Template.boundary_flows

boundary_flows

Residual open stabilizer flows used to close circuit frontiers.

attr bloq.ir.Template.circuit

circuit

The template’s circuit, in template-local qubit coordinates.

attr bloq.ir.Template.detectors

detectors

Detectors closing entirely within this template.

attr bloq.ir.Template.repeat_states

repeat_states

Loop-carried detector recurrences for the circuit’s repeat bodies.

attr bloq.ir.Template.restarts

restarts

Restart syndromes for RUS regions instantiating this template.

class bloq.ir.TemplateInstance

class TemplateInstance

One placement of a pooled template, listed in QuantumNode.instances: template template_id (look it up with Bloq.template()) laid down at layout offset offset, under instance id id. Instance ids are program-unique — unlike node ids, they are not level-local — and instance-space references such as InstanceMeasurement key on them.

attr bloq.ir.TemplateInstance.id

id

The program-unique instance id.

attr bloq.ir.TemplateInstance.offset

offset

Layout offset (x, y).

attr bloq.ir.TemplateInstance.provenance

provenance

Compiler provenance for source and spatial-Port-derived instances.

attr bloq.ir.TemplateInstance.template_id

template_id

The id of the backing template in the shared pool.

class bloq.ir.QuantumNode

class QuantumNode

A template-backed quantum node’s payload, reached via BloqNodeKind.Quantum or Bloq.quantum_nodes(). Its operations come from instantiating the templates its instances place from the program’s shared pool (Bloq.template()), not from any per-node circuit. detectors and restarts are the node’s instance-space side tables for chains that close across its instances.

attr bloq.ir.QuantumNode.detector_bundles

detector_bundles

Shared detector bundle uses, in row order after inline detectors.

attr bloq.ir.QuantumNode.detectors

detectors

Inline node detectors; shared rows are in detector_bundles.

attr bloq.ir.QuantumNode.guards

guards

Conditional registrations. Entries absent from these guards are common.

attr bloq.ir.QuantumNode.instances

instances

The template instances this node places.

attr bloq.ir.QuantumNode.restarts

restarts

The node’s repeat-until-success restart syndromes.

attr bloq.ir.QuantumNode.timeline

timeline

Cumulative circuit-round ends from the minimum source z, if present.

class bloq.ir.QuantumGuard

class QuantumGuard

Members and side-table entries registered when one Boolean input is true.

attr bloq.ir.QuantumGuard.detector_bundles

detector_bundles

Indices in the owning node’s shared detector bundle use table.

attr bloq.ir.QuantumGuard.detector_parities

detector_parities

Conditional XOR contributions to detector rows.

attr bloq.ir.QuantumGuard.detectors

detectors

Indexes in the owning node’s detector table.

attr bloq.ir.QuantumGuard.input

input

The owning quantum node’s selector Value input slot.

attr bloq.ir.QuantumGuard.instances

instances

Program-global instance ids selected by this guard.

attr bloq.ir.QuantumGuard.restart_parities

restart_parities

Conditional XOR contributions to restart rows.

attr bloq.ir.QuantumGuard.restarts

restarts

Indexes in the owning node’s restart table.

class bloq.ir.TemporalPipe

class TemporalPipe

A temporal pipe between two source blocks, named by its endpoint lattice positions. Appears on BloqEdge.Quantum edges as the seam’s connecting pipes, and in NodeProvenance.TemporalPipe / MemoryPadding stamps. src and dst are the endpoint block positions (x, y, z); hadamard marks a basis-swapping (H) pipe.

attr bloq.ir.TemporalPipe.dst

dst

Destination block position (x, y, z).

attr bloq.ir.TemporalPipe.hadamard

hadamard

True if the seam applies a Hadamard.

attr bloq.ir.TemporalPipe.src

src

Source block position (x, y, z).

class bloq.ir.PipeSeam

class PipeSeam

One temporal pipe on a BloqEdge.Quantum seam, with the memory-padding templates the compiler recorded for it. padding is None on a hand-built or synthetic edge, and on a pipe whose patch the compiler could not resolve; Bloq.insert_memory_rounds needs every pipe on a seam padded.

attr bloq.ir.PipeSeam.padding

padding

The pipe’s memory-padding provenance, when the compiler recorded it.

attr bloq.ir.PipeSeam.pipe

pipe

The seam’s temporal pipe.

class bloq.ir.PipePadding

class PipePadding

Memory-padding provenance for one temporal pipe on one quantum edge: the precompiled memory-round templates Bloq.insert_memory_rounds instantiates and their layout offset. The owning BloqEdge.Quantum distinguishes temporal-Hadamard sides and may describe a region terminal. Template ids are valid Bloq.template() / Bloq.subdivide_quantum_edge inputs.

attr bloq.ir.PipePadding.looped

looped

Template implementing 1 + r rounds via a REPEAT r body.

attr bloq.ir.PipePadding.offset

offset

Layout offset positioning the templates over the pipe’s cross-section.

attr bloq.ir.PipePadding.one_round

one_round

Template implementing exactly one memory round.

class bloq.ir.MemoryRoundTarget

class MemoryRoundTarget

A level-qualified target for atomic memory-round insertion.

Edge(from_node, to_node, path=None) splits a quantum edge. After(node, path=...) appends after a region body’s terminal quantum node. Paths use (region_node_id, "body") hops, as returned by walk().

class bloq.ir.MemoryRoundTarget.After

class After(node, *, path)

A terminal quantum node inside a region body.

attr bloq.ir.MemoryRoundTarget.After.node

node

attr bloq.ir.MemoryRoundTarget.After.path

path

class bloq.ir.MemoryRoundTarget.Edge

class Edge(from_node, to_node, *, path=None)

A quantum edge at the specified graph level.

attr bloq.ir.MemoryRoundTarget.Edge.from_node

from_node

attr bloq.ir.MemoryRoundTarget.Edge.path

path

attr bloq.ir.MemoryRoundTarget.Edge.to_node

to_node

Classical control and readouts

Value edges connect a producer’s result to a consumer’s input slot. A ClassicalExpr refers to those slots, not directly to arbitrary graph node IDs. Keep operand order and parity constants when interpreting expressions.

Regions contain nested graphs and export values across their boundaries. A retry region exports the accepted attempt’s results. Activation decides whether a node runs; it is separate from the expression’s parity inputs. ValueRole records how dependencies participate in corrected readouts and feedback.

class bloq.ir.ClassicalNode

class ClassicalNode

A classical-dataflow payload. Observable fragments compose through Compose edges; indexed observables expose decoder-backed Corrected and Flip ports.

class bloq.ir.ClassicalNode.Compute

class Compute(expr)

Combinational logic over incoming value slots.

attr bloq.ir.ClassicalNode.Compute.expr

expr

class bloq.ir.ClassicalNode.Discard

class Discard(condition)

Rejects the shot when the condition holds.

attr bloq.ir.ClassicalNode.Discard.condition

condition

class bloq.ir.ClassicalNode.Observable

class Observable(index, measurements, operators)

A parity and boundary recipe. None identifies an unindexed fragment; an index identifies a complete logical readout and its decoder query.

attr bloq.ir.ClassicalNode.Observable.index

index

attr bloq.ir.ClassicalNode.Observable.measurements

measurements

attr bloq.ir.ClassicalNode.Observable.operators

operators

class bloq.ir.ClassicalExpr

class ClassicalExpr

Combinational logic over a classical node’s incoming Value edges: an expression tree walked via kind + operands(). In(slot) reads the producer wired into that slot. Python truth testing raises TypeError; use Bloq.classical_value to evaluate a node with explicit inputs.

meth bloq.ir.ClassicalExpr.is_linear

is_linear() → bool

Whether the expression is XOR-expressible (in/const/not/xor/parity only) — a static backend can fold a linear condition.

meth bloq.ir.ClassicalExpr.operands

operands() → list[ClassicalExpr]

Ordered children: one for not, any number for xor/and/or, and (condition, when_false, when_true) for select. Leaves and compact parity have none; read the latter’s input_slots and value instead.

attr bloq.ir.ClassicalExpr.input_slots

input_slots

Ordered input slots for a compact parity, else None.

attr bloq.ir.ClassicalExpr.kind

kind

"in", "const", "not", "xor", "and", "or", "select", "parity".

Type:

The variant name

attr bloq.ir.ClassicalExpr.slot

slot

The input slot for an in expression, else None.

attr bloq.ir.ClassicalExpr.value

value

The constant bit for a const or parity expression, else None.

class bloq.ir.ClassicalResolution

class ClassicalResolution

What a classical node computes under a fixed predicate assignment.

measurements is the set of measurement sites XORed together (already cancelled: a site reached an even number of times is absent), sign the constant the parity is XORed with, and decoder_observables the exact decoder-flip basis XORed into the value.

The sites are (instance_id, template_measurement_id) pairs rather than InstanceMeasurement records: a resolution exists to be looked up in EmissionPlan.measurements and PlanStim.measurement_columns, which are keyed that way, so the recipe indexes the column maps with no conversion.

attr bloq.ir.ClassicalResolution.decoder_observables

decoder_observables

Decoder observable ids XORed into the value, in ascending order.

attr bloq.ir.ClassicalResolution.measurements

measurements

The measurement sites XORed into the value, in ascending order, as (instance_id, template_measurement_id) pairs.

attr bloq.ir.ClassicalResolution.sign

sign

The constant XORed into the parity.

class bloq.ir.ValueInput

class ValueInput

A Boolean or composition input, returned by value_inputs() or data_inputs(). The producer feeds the consumer’s slot with the selected output and role; output=None identifies structural recipe composition.

attr bloq.ir.ValueInput.output

output

Selected Boolean output; None denotes structural composition.

attr bloq.ir.ValueInput.producer

producer

The producer node id.

attr bloq.ir.ValueInput.role

role

The input edge’s role.

attr bloq.ir.ValueInput.slot

slot

The consumer input slot this producer feeds.

class bloq.ir.ObservableOutput

class ObservableOutput

Selects an observable’s corrected parity or its decoder flip estimate.

attr bloq.ir.ObservableOutput.Corrected

Corrected = ObservableOutput.Corrected

attr bloq.ir.ObservableOutput.Flip

Flip = ObservableOutput.Flip

class bloq.ir.ValueRef

class ValueRef(node: int, output: ObservableOutput = ObservableOutput.Corrected)

A level-local Boolean source, including its selected output port.

attr bloq.ir.ValueRef.node

node

attr bloq.ir.ValueRef.output

output

class bloq.ir.ValueRole

class ValueRole

Edge provenance on a Value edge (BloqEdge.Value.role, ValueInput.role): what source construct routed this bit here. Value semantics ignore it — every role reads the producer’s bit the same way. Data is plain dataflow; FeedbackFold marks a Feedback action’s condition bit folding into an observable. ReadoutFold folds an earlier corrected readout; dynamic decoder symptoms exclude both runtime folds.

class bloq.ir.ValueRole.Data

class Data

Plain dataflow.

class bloq.ir.ValueRole.FeedbackFold

class FeedbackFold(action)

Folds a Feedback action’s condition bit into an observable. action is the source Feedback ordinal.

attr bloq.ir.ValueRole.FeedbackFold.action

action

class bloq.ir.ValueRole.ReadoutFold

class ReadoutFold

Folds an already corrected readout into a composed named parity.

class bloq.ir.RegionNode

class RegionNode

A structured control-flow region’s payload, reached via BloqNodeKind.Region: a node whose body is a nested SubGraph over the same shared template pool. Restart predicates use incoming Value edges or a body-local restart_source. Edges never cross region boundaries.

class bloq.ir.RegionNode.RepeatUntilSuccess

class RepeatUntilSuccess(body, restart_condition, restart_source)

Region carrying a postselection/restart predicate. Native execution retries failed physical or decoded attempts up to its configured cap.

attr bloq.ir.RegionNode.RepeatUntilSuccess.body

body

attr bloq.ir.RegionNode.RepeatUntilSuccess.restart_condition

restart_condition

attr bloq.ir.RegionNode.RepeatUntilSuccess.restart_source

restart_source

The body-local Boolean source feeding the predicate’s unfed slots.

attr bloq.ir.RegionNode.kind

kind

Which region this is, without destructuring its payload.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> kinds = {n.region.kind for _, n in program.nodes() if n.is_region()}
>>> bloq.ir.RegionKind.RepeatUntilSuccess in kinds
True

class bloq.ir.RegionKind

class RegionKind

What kind of control flow a region node implements.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.T_GATE.load(), distance=3)
>>> len(program.regions_of(bloq.ir.RegionKind.RepeatUntilSuccess)) >= 1
True

attr bloq.ir.RegionKind.RepeatUntilSuccess

RepeatUntilSuccess = RegionKind.RepeatUntilSuccess

class bloq.ir.RegionRef

class RegionRef

A program-unique address of one region node: the level it lives at plus its level-local id.

path is in the same (owner_node_id, body_selector) shape as WalkNode.path, so it can be passed straight back to any path= argument.

meth bloq.ir.RegionRef.body

body(program: Bloq) → SubGraph

The body subgraph this region executes, read out of program.

Parameters:
program: Bloq

The program the reference came from.

Raises:

InvalidArgumentError – If program has no such region.

meth bloq.ir.RegionRef.resolve

resolve(program: Bloq) → RegionNode

The region node this reference names, read out of program.

Parameters:
program: Bloq

The program the reference came from.

Raises:

InvalidArgumentError – If program has no such region — the usual cause is an edit that recycled node ids since the query ran.

attr bloq.ir.RegionRef.node

node

The region node’s level-local id.

attr bloq.ir.RegionRef.path

path

The (owner_id, selector) hops to the region’s level; empty at the top.

class bloq.ir.InstanceMeasurement

class InstanceMeasurement

One measurement site inside a template instance (i<instance>:m<index>).

Ordered by (instance, measurement), matching the IR’s own order, so a collection gathered from several detectors has a stable total order. Instance ids are allocation order, not emission order: an edit that splices padding into the middle of a program gives it the highest instance id, so sorting does not recover the emission sequence.

attr bloq.ir.InstanceMeasurement.instance

instance

The template instance id.

attr bloq.ir.InstanceMeasurement.measurement

measurement

The measurement index within that instance’s template circuit.

class bloq.ir.FramePair

class FramePair

One terminal output’s logical Pauli-frame sign bits: the Compute nodes carrying the X- and Z-frame corrections for the source output port.

attr bloq.ir.FramePair.port

port

The source output port this frame corrects.

attr bloq.ir.FramePair.x

x

The node id whose bit is the X-frame sign.

attr bloq.ir.FramePair.z

z

The node id whose bit is the Z-frame sign.

Detectors and restart syndromes

Detector and restart parities reference measurements in template-local or placed-instance coordinates. A parity can also contain a constant sign or loop-carried state, so a list of measurement indices alone may be incomplete.

Quantum nodes contain both inline detector rows and shared DetectorBundleUse entries. Each use binds a bundle’s owner slots to instances and adds its placement offset. Include both representations when counting or emitting detectors; use activation applies to the whole bundle use.

class bloq.ir.DetectorTerm

class DetectorTerm

One XOR term of a NodeParity: a template-instance measurement or a loop-carried detector state.

class bloq.ir.DetectorTerm.LoopState

class LoopState(state)

attr bloq.ir.DetectorTerm.LoopState.state

state

class bloq.ir.DetectorTerm.Measurement

class Measurement(measurement)

attr bloq.ir.DetectorTerm.Measurement.measurement

measurement

class bloq.ir.TemplateParity

class TemplateParity

An XOR of template-local terms — a detector, restart, or recurrence parity in template space. Measurement terms are circuit-local measurement ids of the owning template’s circuit; translate them to instance space through an EmissionPlan’s measurements map.

attr bloq.ir.TemplateParity.loop_states

loop_states

The loop-state-id terms, in term order.

attr bloq.ir.TemplateParity.measurements

measurements

The template-local measurement-id terms, in term order.

attr bloq.ir.TemplateParity.sign

sign

Whether this parity includes the constant XOR term.

class bloq.ir.TemplateDetector

class TemplateDetector

A detector closing entirely within one template, in template-local measurement space.

attr bloq.ir.TemplateDetector.body

body

The repeat body the detector fires in, or None at the template’s top level.

attr bloq.ir.TemplateDetector.coords

coords

Decoder coordinates, or None when the detector carries none.

attr bloq.ir.TemplateDetector.parity

parity

The detector’s measurement parity.

class bloq.ir.TemplateRestart

class TemplateRestart

A RepeatUntilSuccess restart syndrome in template-local measurement space: when the parity is odd (failure), the enclosing RUS attempt restarts.

attr bloq.ir.TemplateRestart.parity

parity

The restart syndrome parity.

class bloq.ir.TemplateRepeatState

class TemplateRepeatState

A loop-carried detector recurrence on one repeat body, in template-local measurement space: initial seeds the state on the first iteration, next advances it on every later one.

attr bloq.ir.TemplateRepeatState.body

body

The repeat body id.

attr bloq.ir.TemplateRepeatState.initial

initial

The parity on the first iteration.

attr bloq.ir.TemplateRepeatState.next

next

The parity recurrence for subsequent iterations.

attr bloq.ir.TemplateRepeatState.state

state

The loop-state id this recurrence carries.

class bloq.ir.NodeParity

class NodeParity

An XOR of measurement (and loop-state) terms — a detector or restart parity in instance-measurement space.

meth bloq.ir.NodeParity.is_empty

is_empty() → bool

True if the parity has no terms.

meth bloq.ir.NodeParity.loop_states

loop_states() → list[int]

The loop-state ids among the terms (a loop-carried detector recurrence), in term order.

meth bloq.ir.NodeParity.measurements

measurements() → list[InstanceMeasurement]

The measurement terms, dropping any loop-state terms.

meth bloq.ir.NodeParity.terms

terms() → list[DetectorTerm]

All XOR terms in order: measurements and loop states.

attr bloq.ir.NodeParity.sign

sign

Whether this parity includes the constant XOR term.

class bloq.ir.NodeDetector

class NodeDetector

One top-level detector on a quantum node: a parity and optional decoder coordinates.

attr bloq.ir.NodeDetector.coords

coords

Decoder coordinates, or None when the detector carries none.

attr bloq.ir.NodeDetector.parity

parity

The detector’s measurement parity.

class bloq.ir.NodeRestart

class NodeRestart

A RepeatUntilSuccess restart syndrome composed across a template seam, listed in QuantumNode.restarts. Produced when a post-selected parity’s chain crosses two template instances, so neither template’s local table can carry it. When parity is odd (the failure syndrome), the enclosing repeat-until-success attempt restarts. Only meaningful on a node inside a RepeatUntilSuccess body.

attr bloq.ir.NodeRestart.parity

parity

The parity that, when odd (failure syndrome), restarts the RUS attempt.

class bloq.ir.DetectorBundle

class DetectorBundle

Detector rows shared by placed uses of a bundle.

attr bloq.ir.DetectorBundle.detectors

detectors

Rows in bundle order.

attr bloq.ir.DetectorBundle.owner_templates

owner_templates

Expected template id for each owner slot.

class bloq.ir.DetectorBundleUse

class DetectorBundleUse

Bind a shared detector bundle to instances at a layout offset.

attr bloq.ir.DetectorBundleUse.bundle

bundle

Shared bundle pool id.

attr bloq.ir.DetectorBundleUse.instances

instances

Instance id bound to each owner slot.

attr bloq.ir.DetectorBundleUse.offset

offset

Added to each detector center when placed.

class bloq.ir.BundleDetector

class BundleDetector

One shared detector row in bundle-local owner coordinates.

attr bloq.ir.BundleDetector.coords

coords

Decoder coordinates before placement offset.

attr bloq.ir.BundleDetector.sign

sign

Expected parity sign.

attr bloq.ir.BundleDetector.terms

terms

Ordered measurement and loop-state terms.

class bloq.ir.BundleDetectorTerm

class BundleDetectorTerm

One shared detector row in bundle-local owner coordinates.

class bloq.ir.BundleDetectorTerm.LoopState

class LoopState(state)

attr bloq.ir.BundleDetectorTerm.LoopState.state

state

class bloq.ir.BundleDetectorTerm.Measurement

class Measurement(owner, measurement)

attr bloq.ir.BundleDetectorTerm.Measurement.measurement

measurement

attr bloq.ir.BundleDetectorTerm.Measurement.owner

owner

Logical boundaries and provenance

Boundary operators bind logical Pauli support to a particular instance and its input or output face. A LogicalOutput retains its owning instance: equal qubit support does not make two physical cuts interchangeable.

Node and instance provenance link compiled work to source blocks, actions, and module placements. Use that provenance for source-aware inspection, and allow for synthetic nodes that have no authored origin.

class bloq.ir.LogicalOutput

class LogicalOutput

Complete terminal logical operators for one output, in layout-global coordinates.

attr bloq.ir.LogicalOutput.instance

instance

Template instance that owns this output’s logical worldline.

attr bloq.ir.LogicalOutput.port

port

attr bloq.ir.LogicalOutput.x

x

attr bloq.ir.LogicalOutput.z

z

class bloq.ir.InstanceBoundaryOperator

class InstanceBoundaryOperator

A symbolic logical boundary operator at one template instance’s face — one binding payload element of ClassicalNode.Observable.operators. Names the operator by instance reference, never per-shot bits: instance is the TemplateInstance.id, face the temporal face bound, and operator maps instance-global (x, y) qubit coordinates to Pauli terms.

attr bloq.ir.InstanceBoundaryOperator.face

face

Which temporal face (Input or Output) the operator binds.

attr bloq.ir.InstanceBoundaryOperator.instance

instance

The template instance id this operator binds to.

attr bloq.ir.InstanceBoundaryOperator.operator

operator

The operator as a dict mapping instance-global (x, y) qubit coordinates to Pauli terms.

class bloq.ir.BoundaryFace

class BoundaryFace

Which temporal face of a template instance a boundary operator binds — see InstanceBoundaryOperator.face. The face fixes emission position: an Input operator reads the qubit state entering the instance, so it emits before the instance circuit; an Output operator reads on exit, so it emits after.

attr bloq.ir.BoundaryFace.Input

Input = BoundaryFace.Input

attr bloq.ir.BoundaryFace.Output

Output = BoundaryFace.Output

class bloq.ir.BoundaryFlow

class BoundaryFlow

One compiler-authored open stabilizer flow in template-local coordinates.

measurements contains template-local measurement ids. Resolve them through the owning instance and an [PyEmissionPlan]’s measurements map before emitting records.

attr bloq.ir.BoundaryFlow.center

center

Flow-center coordinate, when present.

attr bloq.ir.BoundaryFlow.end

end

Pauli boundary leaving the template.

attr bloq.ir.BoundaryFlow.marker

marker

One of "detector", "discard", or "restart".

attr bloq.ir.BoundaryFlow.measurements

measurements

Template-local measurement ids accumulated by the flow.

attr bloq.ir.BoundaryFlow.sign

sign

Expected XOR when both boundaries have positive eigenvalue.

attr bloq.ir.BoundaryFlow.start

start

Pauli boundary entering the template.

class bloq.ir.NodeProvenance

class NodeProvenance

Node provenance: what source-level construct an IR node realizes, read from BloqNode.provenance. Quantum nodes tie back to source blocks and pipes, classical nodes to stabilizer generators, source actions, or output frames. Provenance is never consulted for emission semantics — its consumers are Bloq.output_frames(), program views, and decoder runtimes. Dispatch on the variant with isinstance.

class bloq.ir.NodeProvenance.Action

class Action(ordinal)

A classical node lowered from the source action at ordinal.

attr bloq.ir.NodeProvenance.Action.ordinal

ordinal

class bloq.ir.NodeProvenance.BlockComponent

class BlockComponent(members)

A fused component of source blocks.

attr bloq.ir.NodeProvenance.BlockComponent.members

members

class bloq.ir.NodeProvenance.BranchSelector

class BranchSelector(name)

A structural branch or selective measurement’s scoped selector name.

attr bloq.ir.NodeProvenance.BranchSelector.name

name

class bloq.ir.NodeProvenance.Generator

class Generator(ordinal)

A classical node realizing stabilizer generator ordinal’s readout.

attr bloq.ir.NodeProvenance.Generator.ordinal

ordinal

class bloq.ir.NodeProvenance.MemoryPadding

class MemoryPadding(pipe, rounds)

Memory-round padding spliced into a seam post-compile, waiting rounds syndrome-extraction rounds.

attr bloq.ir.NodeProvenance.MemoryPadding.pipe

pipe

attr bloq.ir.NodeProvenance.MemoryPadding.rounds

rounds

class bloq.ir.NodeProvenance.Missing

class Missing

No provenance: hand-built or synthetic.

class bloq.ir.NodeProvenance.OutputFrame

class OutputFrame(port, basis)

The basis-frame correction bit for source output port.

attr bloq.ir.NodeProvenance.OutputFrame.basis

basis

attr bloq.ir.NodeProvenance.OutputFrame.port

port

class bloq.ir.NodeProvenance.SpatialPortSubstitution

class SpatialPortSubstitution(source, role)

Positionless temporal Port derived from an authored spatial Port.

attr bloq.ir.NodeProvenance.SpatialPortSubstitution.role

role

attr bloq.ir.NodeProvenance.SpatialPortSubstitution.source

source

class bloq.ir.NodeProvenance.TemporalPipe

class TemporalPipe(pipe)

A temporal pipe between two blocks.

attr bloq.ir.NodeProvenance.TemporalPipe.pipe

pipe

class bloq.ir.InstanceProvenance

class InstanceProvenance

class bloq.ir.InstanceProvenance.Block

class Block(pos: tuple[int, int, int], kind: BlockKind | str, height: str = 'd', tag: str | None = None, role: str = 'auto')

attr bloq.ir.InstanceProvenance.Block.source

source

class bloq.ir.InstanceProvenance.Pipe

class Pipe(src: tuple[int, int, int], direction: Direction | str, hadamard: bool = False, tag: str | None = None)

attr bloq.ir.InstanceProvenance.Pipe.dst

dst

attr bloq.ir.InstanceProvenance.Pipe.src

src

class bloq.ir.InstanceProvenance.Source

class Source

class bloq.ir.InstanceProvenance.SpatialPortSubstitution

class SpatialPortSubstitution(source, role, part)

attr bloq.ir.InstanceProvenance.SpatialPortSubstitution.part

part

attr bloq.ir.InstanceProvenance.SpatialPortSubstitution.role

role

attr bloq.ir.InstanceProvenance.SpatialPortSubstitution.source

source

Stim backend

Use compile_to_stim for a one-call source-to-circuit workflow, or emit_stim to reuse an existing IR program. Both return a stim.Circuit; use its to_file(path) method to save it. Stim emission requires a supported fixed execution structure; retry regions and unpinned guarded quantum membership need dynamic execution or an explicit supported projection first.

Emission plans and per-node segments expose the lowering for custom consumers. Select dialect="stim" or dialect="clifft" where a text-emission API accepts it. Isolated T-attempt artifacts expose cultivation circuits separately from the whole program. See emission for backend restrictions.

func bloq.compile_to_stim

compile_to_stim(graph: BlockGraph, distance: int = 3, *, noise: float | None = None, limits: Mapping[str, int | None] | None = None) → stim.Circuit

Compiles graph and emits the resulting program as a stim.Circuit.

The whole pipeline in one call, for the common case that never needs the intermediate program. Compiles with the given distance and limits, then calls emit_stim(program, noise=noise) with identical results.

Parameters:
graph: BlockGraph

The block graph to compile.

distance: int = 3

The odd code distance to compile at, in 3..=255.

noise: float | None = None

Uniform circuit-level noise probability, as in emit_stim.

limits: Mapping[str, int | None] | None = None

Compiler budget overrides; non-negative counts impose a budget, None disables it, and omitted fields keep their defaults.

Raises:
  • CompileError – If compilation fails.

  • InvalidArgumentError – If the distance, noise, or a limit field is invalid.

  • OverflowError – If a limit count is negative or exceeds usize.

  • StimEmissionError – If the static backend cannot emit the program.

Emits:

CompileWarning: Once per advisory the compile recorded.

Examples

>>> import bloq
>>> circuit = bloq.compile_to_stim(bloq.GalleryItem.X_MEMORY.load())
>>> circuit.num_qubits > 0
True
>>> "DEPOLARIZE" in str(bloq.compile_to_stim(bloq.GalleryItem.X_MEMORY.load(), noise=0.001))
True

func bloq.emit_stim

emit_stim(program: Bloq, *, noise: float | None = None, validate: bool = False, align_moments: bool = False) → stim.Circuit

Emits program as a stim.Circuit, ready for sampling or saving with circuit.to_file(path). Use str(circuit) when circuit text is needed.

Parameters:
program: Bloq

The compiled Bloq IR program to emit.

noise: float | None = None

Uniform probability for gate, reset, measurement, and idle noise, in the inclusive range [0, 1]. None (the default) emits the noiseless circuit.

validate: bool = False

Check the program’s well-formedness before emitting. Defaults to False, which suits a program that came straight from compile() in this process. Pass True for one loaded with Bloq.from_binary() / Bloq.load(), edited by hand, or produced elsewhere: the backend assumes a well-formed program and may otherwise emit a silently wrong circuit.

align_moments: bool = False

Flatten repeats and merge compatible Clifford moments by z layer. Requires noiseless emission; defaults to False.

Raises:

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> bloq.emit_stim(program).num_qubits > 0
True
>>> "DEPOLARIZE1" in str(bloq.emit_stim(program, noise=1e-3))
True
>>> bloq.emit_stim(bloq.Bloq.from_binary(program.to_binary()), validate=True) \
...     == bloq.emit_stim(program)
True

class bloq.ir.EmissionPlan

class EmissionPlan

A quantum node’s merged circuit plus the maps relating instance-space ids to it — the per-node unit a backend emits. measurements translates each instance-space measurement (as an (instance_id, template_measurement_id) key, matching InstanceMeasurement.instance/.measurement) to its merged circuit measurement id; bodies translates each (instance_id, template_body_id) to its merged body id. Side tables named in instance space (node detectors, accumulates, repeat states) resolve against these maps.

Classical and region nodes have no instances and yield an empty plan.

meth bloq.ir.EmissionPlan.normalized_template

normalized_template(id: int) → Template | None

The source template after repeat expansion for this noisy plan, or None when the original program template still applies.

Read side tables using plan.normalized_template(id) or program.template(id). Expansion keeps template ids but updates detector/restart recurrences and body scopes.

attr bloq.ir.EmissionPlan.bodies

bodies

(instance_id, template_body_id) → merged body id.

attr bloq.ir.EmissionPlan.circuit

circuit

The node’s instances translated by offset and merged into one circuit.

attr bloq.ir.EmissionPlan.measurements

measurements

(instance_id, template_measurement_id) → merged measurement id.

func bloq.emit_plan_stim

emit_plan_stim(plan: EmissionPlan, qubit_map: Mapping[tuple[int, int], int], *, dialect: str = 'stim', tag: str | None = None) → PlanStim

Lowers one node’s emission plan to Stim text over a caller-chosen layout.

Parameters:
plan: EmissionPlan

The node’s EmissionPlan (from Bloq.emission_plan).

qubit_map: Mapping[tuple[int, int], int]

Every (x, y) layout coordinate the plan touches, mapped to its Stim qubit index. A coordinate the plan uses but the map omits is an error, so the usual source is the whole program’s layout: {c: i for i, c in enumerate(program.sorted_layout_coords())}.

dialect: str = 'stim'

"stim" (default) or "clifft", case-insensitive. Stim uses S/S_DAG tagged HONEST_T for T gates; Clifft keeps literal T/T_DAG gates.

tag: str | None = None

Optional Stim instruction tag applied to the emitted gates.

Raises:

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> layout = {c: i for i, c in enumerate(program.sorted_layout_coords())}
>>> node = program.deterministic_emit_order()[0]
>>> lowered = bloq.emit_plan_stim(program.emission_plan(node), layout)
>>> lowered.measurement_count > 0
True
>>> max(lowered.measurement_columns.values()) < lowered.measurement_count
True

class bloq.PlanStim

class PlanStim

One lowered emission plan: its Stim text plus where its measurements landed.

measurement_columns maps each instance-space measurement — the (instance_id, template_measurement_id) keys of EmissionPlan.measurements — to its column in text after every REPEAT block is unrolled, counting from 0 within this plan. Add the plan’s own offset to place it in a larger circuit. measurement_count is how many columns text produces in total, which is that same offset for the next plan.

attr bloq.PlanStim.measurement_columns

measurement_columns

(instance_id, template_measurement_id) → post-unroll column.

attr bloq.PlanStim.measurement_count

measurement_count

Total measurement columns the text produces.

attr bloq.PlanStim.text

text

The lowered Stim text.

func bloq.emit_stim_segments

emit_stim_segments(program: Bloq, *, noise: float | None = None, validate: bool = False) → StimSegments

Emits program as per-node Stim segments (see StimSegments).

Parameters:
program: Bloq

The compiled Bloq IR program to emit.

noise: float | None = None

Uniform probability for gate, reset, measurement, and idle noise, in the inclusive range [0, 1]. None (the default) emits the noiseless circuit.

validate: bool = False

Check the program’s well-formedness before emitting; see emit_stim(). Defaults to False.

Raises:

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> segments = bloq.emit_stim_segments(program)
>>> segments.header.startswith("QUBIT_COORDS")
True
>>> len(segments.segments) == program.node_count
True
>>> import stim
>>> stim.Circuit(segments.to_text()) == bloq.emit_stim(program)
True
>>> stim.Circuit(bloq.emit_stim_segments(program, noise=1e-3).to_text()) \
...     == bloq.emit_stim(program, noise=1e-3)
True

func bloq.emit_stim_segments_pair

emit_stim_segments_pair(program: Bloq, *, noise: float) → tuple[StimSegments, StimSegments]

Emits program twice from one pass: noiseless segments and segments with uniform circuit-level noise, chunked identically.

Both results carry the same node ids and the same measurement spans, so a caller comparing or splicing the two — the usual noise-injection workflow — no longer has to emit twice and assert the chunkings agree.

Parameters:
program: Bloq

The compiled Bloq IR program to emit.

noise: float

Uniform probability for gate, reset, measurement, and idle noise, in the inclusive range [0, 1].

Returns:

The clean and noisy segmentations.

Return type:

tuple[StimSegments, StimSegments]

Raises:

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> clean, noisy = bloq.emit_stim_segments_pair(program, noise=1e-3)
>>> [s.node_id for s in clean.segments] == [s.node_id for s in noisy.segments]
True
>>> import stim
>>> stim.Circuit(clean.to_text()) == bloq.emit_stim(program)
True

class bloq.StimSegment

class StimSegment

One node’s chunk of a segmented Stim program.

text is the node’s Stim text; measurement_start is the absolute column of its first measurement in the whole program, and measurement_count how many it contributes — so this segment owns program columns measurement_start .. measurement_start + measurement_count.

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> segment = bloq.emit_stim_segments(program).segments[0]
>>> segment.measurement_start
0
>>> segment.measurement_count > 0
True

attr bloq.StimSegment.measurement_count

measurement_count

How many measurement columns this chunk contributes.

attr bloq.StimSegment.measurement_start

measurement_start

Absolute column of this chunk’s first measurement.

attr bloq.StimSegment.node_id

node_id

The id of the node this chunk was emitted from.

attr bloq.StimSegment.text

text

The node’s Stim text.

class bloq.StimSegments

class StimSegments

A Stim program linearized into per-node chunks, for callers transforming nodes in isolation (chiefly noise injection that must leave port MPP boundaries noiseless). Plain emission wants emit_stim.

The header holds the shared QUBIT_COORDS preamble; segments holds one StimSegment per node in emission order. to_text() reassembles the raw circuit text; stim.Circuit(segments.to_text()) matches emit_stim(program).

Examples

>>> import bloq
>>> program = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> segments = bloq.emit_stim_segments(program)
>>> "QUBIT_COORDS" in segments.header
True
>>> len(segments.segments) >= 1
True
>>> import stim
>>> stim.Circuit(segments.to_text()) == bloq.emit_stim(program)
True

meth bloq.StimSegments.to_text

to_text() → str

The header and every chunk concatenated — the whole-program Stim text.

attr bloq.StimSegments.header

header

QUBIT_COORDS preamble shared by every node.

attr bloq.StimSegments.num_measurements

num_measurements

The total number of measurement columns across every chunk.

attr bloq.StimSegments.segments

segments

Per-node chunks in emission order.

func bloq.remap_stim_circuit

remap_stim_circuit(text: str, qubit_map: Mapping[int, int], *, skip: set[str] | None = None, honest_t: bool = False, observable_map: Mapping[int, collections.abc.Sequence[int]] | None = None, measurement_map: Mapping[int, int] | None = None, source_measurement_start: int = 0, destination_measurement_start: int = 0) → tuple[str, dict[int, int]]

Flattens and remaps Stim circuit text without constructing Python target objects.

Parameters:
text: str

A Stim circuit.

qubit_map: Mapping[int, int]

Source qubit index to destination qubit index.

skip: set[str] | None = None

Instruction names to omit; defaults to omitting nothing. A skipped instruction still advances the source measurement offset, so dropping "QUBIT_COORDS" does not shift the record mapping.

honest_t: bool = False

Replace tags on S and S_DAG with HONEST_T.

observable_map: Mapping[int, collections.abc.Sequence[int]] | None = None

Optional source observable to destination observables.

measurement_map: Mapping[int, int] | None = None

Optional absolute source-to-destination measurement map.

source_measurement_start: int = 0

Absolute source measurement offset.

destination_measurement_start: int = 0

Absolute destination measurement offset.

Returns:

Remapped Stim text and newly produced measurement-map entries.

Return type:

tuple[str, dict[int, int]]

Raises:

InvalidArgumentError – If Stim text or a requested mapping is invalid.

func bloq.stim_to_clifft_text

stim_to_clifft_text(text: str) → str

Rewrites Stim text into Clifft text: every S / S_DAG tagged HONEST_T_TAG becomes T / T_DAG, and untagged gates are left alone.

Parameters:
text: str

Stim circuit text.

Examples

>>> import bloq
>>> bloq.stim_to_clifft_text("S[HONEST_T] 0")
'T 0'
>>> bloq.stim_to_clifft_text("S 0")
'S 0'

func bloq.clifft_to_stim_text

clifft_to_stim_text(text: str) → str

Rewrites Clifft text into Stim text: every T / T_DAG becomes S / S_DAG tagged HONEST_T_TAG.

Lossy in one direction: EXP_VAL lines have no Stim spelling and are dropped. stim_to_clifft_text inverts the gate mapping, not the drop.

Parameters:
text: str

Clifft circuit text.

Examples

>>> import bloq
>>> bloq.clifft_to_stim_text("T 0")
'S[HONEST_T] 0'

func bloq.emit_isolated_t_attempts

emit_isolated_t_attempts(program: Bloq, *, noise: float) → IsolatedTAttemptArtifacts

Emits the physical S/honest-T circuits and shared causal GAP companions for one isolated T-source attempt.

program must be the compiled isolated T -> +Z -> Port fixture. Insert any required memory rounds with Bloq.insert_memory_rounds_after before calling this function.

Parameters:
program: Bloq

The prepared isolated-T Bloq IR program.

noise: float

Uniform circuit-level error probability in the inclusive range [0, 1], spelled as in emit_stim().

Raises:

class bloq.IsolatedTAttemptArtifacts

class IsolatedTAttemptArtifacts

Clifft physical circuits and Stim causal companions for one isolated-T source attempt.

attr bloq.IsolatedTAttemptArtifacts.companion

companion

Partially-noiseless S-proxy Stim companion carrying the GAP pair.

attr bloq.IsolatedTAttemptArtifacts.manifest

manifest

Dense-column alignment data shared by all four circuits.

attr bloq.IsolatedTAttemptArtifacts.physical_s

physical_s

Full-noise S-control Clifft circuit with direct X/Y/Z probes.

attr bloq.IsolatedTAttemptArtifacts.physical_t

physical_t

Full-noise honest-T Clifft circuit with direct X/Y/Z probes.

attr bloq.IsolatedTAttemptArtifacts.sheets

sheets

Terminal stabilizer frontier sheets, as a suffix to companion.

class bloq.IsolatedTAttemptManifest

class IsolatedTAttemptManifest

Detector, frame, GAP, frontier, and probe columns for one isolated-T attempt artifact.

The frontier_* lists are parallel. Frontier entry i maps to synthetic detector base_companion_detector_count + i in the causal DEM transform. The exp_val_signs list is ordered X, Y, Z. Each corrected frame XORs its measurement parity, frame_*_sign, and the associated GAP prediction.

attr bloq.IsolatedTAttemptManifest.detector_signs

detector_signs

Expected noiseless parity of every detector, in emitted order.

attr bloq.IsolatedTAttemptManifest.exp_val_signs

exp_val_signs

Static signs multiplying direct X/Y/Z EXP_VAL probes.

attr bloq.IsolatedTAttemptManifest.frame_x_gap_observable

frame_x_gap_observable

GAP observable whose correction contributes to the X-frame bit.

attr bloq.IsolatedTAttemptManifest.frame_x_measurements

frame_x_measurements

Measurement columns XORed into the output X-frame bit.

attr bloq.IsolatedTAttemptManifest.frame_x_sign

frame_x_sign

Constant XORed with the X-frame measurement parity before decoder correction.

attr bloq.IsolatedTAttemptManifest.frame_z_gap_observable

frame_z_gap_observable

GAP observable whose correction contributes to the Z-frame bit.

attr bloq.IsolatedTAttemptManifest.frame_z_measurements

frame_z_measurements

Measurement columns XORed into the output Z-frame bit.

attr bloq.IsolatedTAttemptManifest.frame_z_sign

frame_z_sign

Constant XORed with the Z-frame measurement parity before decoder correction.

attr bloq.IsolatedTAttemptManifest.frontier_bases

frontier_bases

Frontier stabilizer bases.

attr bloq.IsolatedTAttemptManifest.frontier_observables

frontier_observables

Frontier observable ids, parallel with frontier_bases and frontier_signs.

attr bloq.IsolatedTAttemptManifest.frontier_signs

frontier_signs

Expected frontier parities.

attr bloq.IsolatedTAttemptManifest.gap_x_observable

gap_x_observable

Logical-X GAP observable id.

attr bloq.IsolatedTAttemptManifest.gap_z_observable

gap_z_observable

Logical-Z GAP observable id.

attr bloq.IsolatedTAttemptManifest.postselection_detectors

postselection_detectors

Detector columns used for physical restart postselection.

attr bloq.IsolatedTAttemptManifest.rus_path

rus_path

(region_id, body_selector) hops to the emitted RUS body.

VM verification

lower_vm prepares a reusable VmProgram; each run executes a dynamic shot with its own seed and runtime limits. Check VmRunResult.discarded before requesting corrected logical Bloch vectors, because a discarded shot has no committed logical result.

The VM verifies measurement-dependent control and physical output states using mock decoding and timing models. Its traces explain execution, but are not a stable program persistence format or a claim about decoder performance. See VM verification for model assumptions.

func bloq.lower_vm

lower_vm(program: Bloq, *, noise: float = 0.0, gate_duration: float = 1.0, decoder_latency_rounds: int = 10, source_release_time: float = 0.0, input_release_time: float | None = None, factory_release_time: float = 0.0, max_quantum_variants: int | None = None) → VmProgram

Lowers Bloq IR once to a reusable dynamic VM program.

Parameters:
program: Bloq

Compiled Bloq IR.

noise: float = 0.0

Uniform circuit and idle-noise probability.

gate_duration: float = 1.0

Duration of each nonempty physical moment; must exceed 1e-9.

decoder_latency_rounds: int = 10

Mock-decoder latency in local memory rounds.

source_release_time: float = 0.0

Release epoch for Clifford sources.

input_release_time: float | None = None

External-input release epoch; defaults to source_release_time.

factory_release_time: float = 0.0

Release epoch for resource factories.

max_quantum_variants: int | None = None

Maximum jointly reachable guard tuples for one quantum stage. Defaults to 4096.

Returns:

A reusable VmProgram. Prepared-Y release offsets follow the emitted preparation durations.

Raises:

Examples

>>> import bloq
>>> ir = bloq.compile(bloq.GalleryItem.X_MEMORY.load(), distance=3)
>>> vm = bloq.lower_vm(ir)
>>> vm.task_count > 0
True

class bloq.VmProgram

class VmProgram

A Bloq IR program lowered once to the dynamic VM instruction stream.

meth bloq.VmProgram.run

run(*, seed: int = 0, input_state: str = 'plus', decoder_acceptance: float = 0.8, accepted_accuracy: float = 0.999, rejected_accuracy: float = 0.9, gap_threshold: float = 0.5, idle_error_rate: float | None = None, max_steps: int = 1000000, max_attempts: int = 100) → VmRunResult

Runs one dynamic shot with the Ticit tableau backend.

Parameters:
seed: int = 0

Root seed for physical noise and mock-decoder draws.

input_state: str = 'plus'

Encoded external input, "plus" or "zero".

decoder_acceptance: float = 0.8

Mock decoder acceptance probability.

accepted_accuracy: float = 0.999

Residual accuracy for accepted solves.

rejected_accuracy: float = 0.9

Residual accuracy for rejected solves.

gap_threshold: float = 0.5

Confidence threshold, strictly between 0 and 1.

idle_error_rate: float | None = None

Optional dynamic-idle depolarization rate per time unit. Omit to use the rate derived from lower_vm(noise=...).

max_steps: int = 1000000

Maximum task, moment, and memory-round executions.

max_attempts: int = 100

Maximum attempts of one repeat-until-success task.

Raises:

meth bloq.VmProgram.to_json

to_json(*, indent: int | None = None) → str

Serializes the complete executable instruction stream as JSON.

This includes tasks, gates, dependencies, entry stream, logical inputs, logical outputs, and source release times. It is an inspection format, not a stable persistence protocol.

Parameters:
indent: int | None = None

None for compact JSON or 2 for pretty JSON.

Raises:

attr bloq.VmProgram.decoder_latency_rounds

decoder_latency_rounds

Configured mock-decoder latency carried by this program, in memory rounds.

attr bloq.VmProgram.output_count

output_count

Number of terminal logical outputs.

attr bloq.VmProgram.qubit_count

qubit_count

Number of simulator qubits.

attr bloq.VmProgram.sources

sources

Independently released source tasks in dense task order.

attr bloq.VmProgram.task_count

task_count

Number of VM tasks across all dynamic regions.

class bloq.VmRunResult

class VmRunResult

One dynamic shot: a JSON-ready trace and terminal logical Bloch vectors.

meth bloq.VmRunResult.logical_bloch

logical_bloch(output: int = 0) → tuple[float, float, float]

Terminal (X, Y, Z) Bloch vector with Pauli-frame corrections.

Parameters:
output: int = 0

Zero-based logical-output index.

Raises:

meth bloq.VmRunResult.to_json

to_json(*, indent: int | None = None) → str

Serializes the trace as compact JSON, or pretty JSON for indent=2.

Parameters:
indent: int | None = None

None for compact JSON or 2 for pretty JSON.

Raises:

attr bloq.VmRunResult.discarded

discarded

Whether the shot ended without a committed result.

attr bloq.VmRunResult.finished_at

finished_at

Physical stop time.

attr bloq.VmRunResult.peak_rank

peak_rank

Highest stabilizer-frame rank reached by the backend.

attr bloq.VmRunResult.trace

trace

Full execution trace as nested Python dictionaries and lists.

ZX logical analysis

Convert a source graph to its ZX diagram and inspect logical stabilizers before physical compilation. This layer describes the source’s logical relation; physical detectors, scheduling, and decoder behavior require the compiled IR and its backends. See logical correlations for the relation between stabilizers and named readouts.

func bloq.to_zx_graph

to_zx_graph(graph: BlockGraph) → ZXGraph

Converts a BlockGraph into its ZX diagram, a read-only ZXGraph.

Parameters:
graph: BlockGraph

The block graph to lower.

Returns:

The derived ZX diagram.

Return type:

ZXGraph

Raises:

BlockGraphError – If the graph does not lower to ZX (e.g. a malformed pipe structure).

Examples

>>> import bloq
>>> zx = bloq.to_zx_graph(bloq.GalleryItem.CNOT.load())
>>> zx.node_count > 0
True
>>> zx.is_clifford_computation
True

class bloq.ZXGraph

class ZXGraph

The ZX diagram derived from a BlockGraph (read-only view).

Build one with to_zx_graph. The ZX layer is an analysis product of a block graph, not an authoring surface: its nodes, edges, and relations are queryable but immutable.

Examples

>>> import bloq
>>> zx = bloq.to_zx_graph(bloq.GalleryItem.CNOT.load())
>>> zx.node_count == len(zx.nodes())
True
>>> zx.is_open
True
>>> zx.is_clifford_computation
True

meth bloq.ZXGraph.edge_between

edge_between(n1: int, n2: int) → ZXEdge | None

An edge between two node ids, or None. The ZX layer is a multigraph: with parallel edges this returns one of them.

Parameters:
n1: int

One endpoint node id.

n2: int

The other endpoint node id.

meth bloq.ZXGraph.edge_id

edge_id(n1: int, n2: int) → int | None

The id of an edge between two node ids, or None. The ZX layer is a multigraph: with parallel edges this returns one of them.

Parameters:
n1: int

One endpoint node id.

n2: int

The other endpoint node id.

meth bloq.ZXGraph.edges

edges() → list[ZXEdge]

All edges.

meth bloq.ZXGraph.is_output_port

is_output_port(node_id: int) → bool

True if node_id is an output port — a Port whose neighbors all sit at a lower z-coordinate.

Parameters:
node_id: int

The node to classify.

Raises:

InvalidArgumentError – If node_id is not a valid node id.

meth bloq.ZXGraph.measurement_columns

measurement_columns() → dict[str, int]

Measurement variable name -> column id in the combined node/edge id space.

meth bloq.ZXGraph.neighbors

neighbors(node_id: int) → list[int] | None

Neighbor node ids of node_id, or None for an unknown id.

Parameters:
node_id: int

The node whose neighbors to return.

meth bloq.ZXGraph.node_at

node_at(pos: tuple[int, int, int]) → ZXNode | None

The node at pos, or None.

Parameters:
pos: tuple[int, int, int]

The (x, y, z) position to look up.

meth bloq.ZXGraph.nodes

nodes() → list[ZXNode]

All nodes, indexable by node id.

meth bloq.ZXGraph.output_ports

output_ports() → list[tuple[int, int, int]]

Output-port positions as (x, y, z) triples, sorted.

A layout column is not a qubit: two output ports can share (x, y) when the second patch reuses tiles the first vacated, so ports are reported with their z-coordinate rather than collapsed to columns.

meth bloq.ZXGraph.stabilizers

stabilizers() → list[StabilizerGenerator]

Derives the stabilizer generators of the diagram.

Raises:

BlockGraphError – If the stabilizers cannot be derived.

meth bloq.ZXGraph.validate_for_program

validate_for_program() → None

Validates that the graph’s actions form a runnable program.

Raises:

BlockGraphError – If the actions do not form a runnable program.

meth bloq.ZXGraph.z_layers

z_layers() → list[int]

The distinct z-coordinates that carry nodes, ascending.

attr bloq.ZXGraph.edge_count

edge_count

The number of edges.

attr bloq.ZXGraph.is_clifford_computation

is_clifford_computation

True if the computation is Clifford (no T or selective nodes).

attr bloq.ZXGraph.is_open

is_open

True if the graph still has unfilled ports.

attr bloq.ZXGraph.node_count

node_count

The number of nodes.

attr bloq.ZXGraph.total_ids

total_ids

The size of the combined node+edge id space.

class bloq.ZXNode

class ZXNode

A node (spider or boundary) of a ZX diagram (read-only view).

Nodes come from ZXGraph.nodes() (indexable by id) or ZXGraph.node_at(). Interior nodes are "X", "Y", or "Z" spiders; the boundary kinds are "Port" (an open boundary left by a port block), "T" (a magic-state boundary), and "Selective(...)" (a boundary whose basis is resolved at runtime). is_boundary is true for all three boundary kinds.

attr bloq.ZXNode.id

id

The node id; also its index into ZXGraph.nodes().

attr bloq.ZXNode.is_boundary

is_boundary

Port, T, and Selective.

Type:

True for all boundary node kinds

attr bloq.ZXNode.is_port

is_port

True if this node is a port.

attr bloq.ZXNode.is_t

is_t

True if this node is a T node.

attr bloq.ZXNode.kind

kind

"X", "Y", "Z", "Port", "T", or "Selective(<bases>)".

Type:

The node kind

attr bloq.ZXNode.pos

pos

The node’s (x, y, z) position.

class bloq.ZXEdge

class ZXEdge

An edge of a ZX diagram (read-only view).

Edges come from ZXGraph.edges() or ZXGraph.edge_between(); each one connects the two nodes n1 / n2 (by node id) and may carry a Hadamard. Edge ids live in the same id space as node ids, following them (the space that ZXGraph.total_ids sizes and stabilizer Pauli strings index into).

attr bloq.ZXEdge.hadamard

hadamard

True if the edge carries a Hadamard.

attr bloq.ZXEdge.id

id

The edge id (edge ids follow node ids in the graph’s id space).

attr bloq.ZXEdge.n1

n1

The id of one endpoint node.

attr bloq.ZXEdge.n2

n2

The id of the other endpoint node.

class bloq.Stabilizer

class Stabilizer

A stabilizer of the block graph’s ZX diagram (read-only view).

Rows come from BlockGraph.stabilizers() (as StabilizerGenerator.stabilizer) and fill_ports_auto(). The operator itself is paulis, a dense Pauli string over the ZX graph’s combined node+edge id space; the same support is also broken out by graph element: port_stabilizer maps open-port positions to Paulis (how the stabilizer meets the outside world), while interior_nodes / interior_edges cover spiders and edges inside the diagram. Row role and measurement identity live on StabilizerGenerator.

attr bloq.Stabilizer.interior_edges

interior_edges

Pauli support on interior edges, keyed by endpoint-position pairs in ascending order.

attr bloq.Stabilizer.interior_nodes

interior_nodes

Pauli support on interior node positions, in ascending position order.

attr bloq.Stabilizer.paulis

paulis

The dense Pauli string over the ZX graph’s combined node+edge id space.

attr bloq.Stabilizer.port_stabilizer

port_stabilizer

Pauli support on external port positions, in ascending position order.

class bloq.StabilizerGenerator

class StabilizerGenerator

A stabilizer generator row: a stabilizer plus its role.

One row of the generator basis returned by BlockGraph.stabilizers() or ZXGraph.stabilizers(). The kind says what the row does: "logical" rows generate the diagram’s logical stabilizer group, "measurement" rows witness a named measurement variable, and "selective_fixing" rows pin the measurement basis of one or more selective nodes. Internal rank rows are not exposed through the graph API.

attr bloq.StabilizerGenerator.is_measurement

is_measurement

True if this row witnesses a measurement variable.

attr bloq.StabilizerGenerator.kind

kind

"measurement", "selective_fixing", or "logical".

Type:

The row’s role

attr bloq.StabilizerGenerator.measurement_name

measurement_name

The measurement variable name, for "measurement" rows.

attr bloq.StabilizerGenerator.selective_fixing_targets

selective_fixing_targets

(position, forbidden_pauli) pairs, for "selective_fixing" rows.

attr bloq.StabilizerGenerator.stabilizer

stabilizer

The underlying stabilizer.

Pauli operators and geometry

Pauli operators and measurement bases describe logical and physical support. PauliString represents Hermitian Pauli support without an explicit phase; retain signs separately when an enclosing readout or parity carries them. Direction identifies a signed lattice direction, while UDirection identifies an unsigned axis.

class bloq.Pauli

class Pauli

A single-qubit Pauli operator (I, X, Y, or Z).

Examples

>>> from bloq import Pauli
>>> Pauli.X.anticommutes(Pauli.Z)
True
>>> Pauli.X.anticommutes(Pauli.X)
False
>>> str(Pauli.X.flip())
'Z'

meth bloq.Pauli.anticommutes

anticommutes(other: Pauli) → bool

Two Paulis anticommute iff both are non-identity and differ.

Parameters:
other: Pauli

The Pauli to test against.

meth bloq.Pauli.flip

flip() → Pauli

Swaps X and Z; leaves I and Y unchanged.

attr bloq.Pauli.I

I = Pauli.I

attr bloq.Pauli.X

X = Pauli.X

attr bloq.Pauli.Y

Y = Pauli.Y

attr bloq.Pauli.Z

Z = Pauli.Z

class bloq.PauliBasis

class PauliBasis

A single-qubit Pauli basis: X, Y, or Z (excludes identity).

A non-identity Pauli axis — unlike Pauli, which also has I. Use it where an axis must be definite: measurement bases in actions, feedback targets (FeedbackTarget.pauli), and compiled-circuit operations. APIs taking one usually also accept its "X" / "Y" / "Z" letter.

attr bloq.PauliBasis.X

X = PauliBasis.X

attr bloq.PauliBasis.Y

Y = PauliBasis.Y

attr bloq.PauliBasis.Z

Z = PauliBasis.Z

class bloq.PauliString

class PauliString(init: int | str)

A dense Pauli operator over a fixed number of qubits.

Build from a qubit count (identity string) or a literal like "XZ_Y" (_ or I marks identity). Indexable and mutable like a list of Pauli.

Examples

>>> from bloq import PauliString
>>> ps = PauliString("XZ_Y")
>>> len(ps), ps.weight()
(4, 3)
>>> str(ps[0])
'X'
>>> str(PauliString(4))
'____'

meth bloq.PauliString.weight

weight() → int

Returns the number of non-identity Paulis.

class bloq.Basis

class Basis

A measurement basis: the Pauli X or Z axis.

Examples

>>> from bloq import Basis
>>> str(Basis.X)
'X'
>>> str(Basis.X.flip())
'Z'

meth bloq.Basis.flip

flip() → Basis

Returns the complementary basis (X <-> Z).

attr bloq.Basis.X

X = Basis.X

attr bloq.Basis.Z

Z = Basis.Z

class bloq.Direction

class Direction

A signed axis direction in the block-graph lattice (+X, -X, …, -Z).

Python variant names are X_PLUS-style; str(d) and Direction.parse(...) use the BLOG spelling ("+X", "-Z", …).

Examples

>>> from bloq import Direction
>>> str(Direction.parse("+X"))
'+X'
>>> str(Direction.X_PLUS.negate())
'-X'
>>> Direction.X_PLUS.vector()
(1, 0, 0)

meth bloq.Direction.parse

static parse(text: str) → Direction

Parses a BLOG direction spelling like "+X" or "-Z".

Parameters:
text: str

A BLOG direction spelling, e.g. "+X" or "-Z" (case-insensitive).

Raises:

InvalidArgumentError – If text is not a valid direction spelling.

meth bloq.Direction.is_spatial

is_spatial() → bool

Returns True for the X/Y (spatial) directions.

meth bloq.Direction.negate

negate() → Direction

Returns the opposite direction along the same axis.

meth bloq.Direction.vector

vector() → tuple[int, int, int]

Returns the unit axis vector (x, y, z) pointing along this direction.

attr bloq.Direction.X_MINUS

X_MINUS = Direction.X_MINUS

attr bloq.Direction.X_PLUS

X_PLUS = Direction.X_PLUS

attr bloq.Direction.Y_MINUS

Y_MINUS = Direction.Y_MINUS

attr bloq.Direction.Y_PLUS

Y_PLUS = Direction.Y_PLUS

attr bloq.Direction.Z_MINUS

Z_MINUS = Direction.Z_MINUS

attr bloq.Direction.Z_PLUS

Z_PLUS = Direction.Z_PLUS

class bloq.UDirection

class UDirection

An unsigned axis (X, Y, or Z).

A lattice axis with no orientation — a Direction with its sign dropped. Use it where only the axis matters, such as the rotation axis of BlockGraph.rotate_about_origin. APIs taking one usually also accept its "X" / "Y" / "Z" letter.

attr bloq.UDirection.X

X = UDirection.X

attr bloq.UDirection.Y

Y = UDirection.Y

attr bloq.UDirection.Z

Z = UDirection.Z

Errors and warnings

Catch BloqError for domain failures, or a specific subclass when recovery depends on the stage: parsing, compilation, IR validation, emission, or VM execution. A resource-limited CompileError means computation stopped at a budget; it does not prove that the source is invalid.

Normal Python errors retain their meaning. Sequence indexing and mapping lookup raise IndexError and KeyError; argument coercion can raise TypeError or OverflowError; filesystem access raises OSError. CompileWarning uses Python’s warnings system for advisories from successful compilation.

class bloq.BloqError

class BloqError

Base exception for bloq domain failures.

Python protocol, argument-conversion, and I/O errors retain their standard builtins, including IndexError, KeyError, TypeError, OverflowError, and OSError.

Examples

>>> import bloq
>>> issubclass(bloq.CompileError, bloq.BloqError)
True
>>> issubclass(bloq.ParseError, bloq.BloqError)
True

class bloq.InvalidArgumentError

class InvalidArgumentError

An argument failed validation, or a lookup key (id, name, position, basis/kind spelling) was not found.

class bloq.ParseError

class ParseError

A .blog source failed to parse (message carries the rendered diagnostic).

class bloq.BlockGraphError

class BlockGraphError

A block-graph operation or validation failed.

class bloq.CompileError

class CompileError

Lowering a block graph to Bloq IR failed.

class bloq.CompileWarning

class CompileWarning

An advisory raised by a successful compile.

A UserWarning subclass, so it is filterable on its own: warnings.filterwarnings("error", category=bloq.CompileWarning) turns compile advisories into exceptions without touching other warnings.

Examples

>>> import bloq, warnings
>>> issubclass(bloq.CompileWarning, UserWarning)
True

class bloq.BloqValidationError

class BloqValidationError

A Bloq IR program failed validation.

class bloq.TextParseError

class TextParseError

A .bloqir text payload failed to parse.

class bloq.BinaryDecodeError

class BinaryDecodeError

A .bloq binary payload failed to decode.

class bloq.StimEmissionError

class StimEmissionError

Emitting a Stim circuit from Bloq IR failed.

class bloq.LowerError

class LowerError

Lowering Bloq IR to a VM program failed.

class bloq.RuntimeError

class RuntimeError

Executing a lowered VM program failed.

Format and metadata constants

Use these constants for codec extensions, version checks, and compiler metadata lookups instead of duplicating their string values. Exchange-format versions identify the serialized layout; __version__ identifies the installed Python package. See Bloq IR for persistence choices.

data bloq.ir.BLOQ_TEXT_EXTENSION

BLOQ_TEXT_EXTENSION = 'bloqir'

data bloq.ir.BLOQ_TEXT_VERSION

BLOQ_TEXT_VERSION = 1

data bloq.ir.BLOQ_BINARY_EXTENSION

BLOQ_BINARY_EXTENSION = 'bloq'

data bloq.ir.BLOQ_BINARY_VERSION

BLOQ_BINARY_VERSION = 1

data bloq.ir.CODE_DISTANCE_METADATA_KEY

CODE_DISTANCE_METADATA_KEY = 'bloq_compile.code_distance'

data bloq.ir.CONVENTION_METADATA_KEY

CONVENTION_METADATA_KEY = 'bloq_compile.convention'

data bloq.ir.CLIFFORD_PROXY_SEED_METADATA_KEY

CLIFFORD_PROXY_SEED_METADATA_KEY = 'bloq_compile.clifford_proxy_seed'

data bloq.HONEST_T_TAG

HONEST_T_TAG = 'HONEST_T'

data bloq.__version__

__version__ = '0.1.2-dev'