Skip to main content

Bloq

Struct Bloq 

Source
pub struct Bloq { /* private fields */ }
Expand description

The compiled bloq circuit IR: a graph of quantum, classical, and region nodes produced by bloq_compile, consumed by emitters and the verifier.

The top level is a SubGraph — the same graph-level type region bodies use — so every read accessor (SubGraph::node, SubGraph::nodes, SubGraph::incoming, …) works uniformly at any nesting level. Bloq delegates the common calls and adds whole-program state (templates, frames, provenance) plus recursive traversal (Bloq::walk, Bloq::levels).

Cloning shares graph levels, quantum payloads, and templates; edits detach the affected storage. Metadata and populated layout caches are still copied.

Implementations§

Source§

impl Bloq

Source

pub fn to_binary(&self) -> Vec<u8> ⓘ

Encode this program as a binary .bloq artifact.

§Panics

Panics if the in-memory IR violates postcard’s sequence contract.

Source

pub fn from_binary(bytes: &[u8]) -> Result<Self, BinaryDecodeError>

Decode a binary .bloq artifact.

Decoding rejects structurally malformed payloads (trailing bytes, duplicate node ids, dangling edges, an implausibly sparse node-id space, unsorted registry/PauliMap entries) but does not check IR semantics — run Bloq::validate on untrusted input.

§Errors

Returns BinaryDecodeError for an invalid header, unsupported version, malformed payload, or trailing data.

Source§

impl Bloq

Source

pub fn insert_memory_rounds( &mut self, target: MemoryRoundTarget, rounds: u32, ) -> Result<BloqNodeId, EditError>

Insert physical memory rounds at a level-qualified quantum edge or after a region body’s terminal quantum node.

Templates come from compiler-recorded padding provenance, so the edit works on a deserialized program without its source graph. The edit is transactional: any error leaves self unchanged.

§Errors

Returns EditError when the target or stored seam provenance is invalid, membership is unresolved, or rounds is zero.

Source

pub fn set_template_repetitions( &mut self, template: TemplateId, repetitions: u32, ) -> Result<(), EditError>

Retune a template’s bulk duration: rewrite the repetition count of its single top-level REPEAT.

This is how a compiled program’s memory-round budget is changed without recompiling, and it is a structural rewrite: neither the template’s side tables nor its boundary flows depend on the repetition count (a loop’s recurrence is stated per iteration), so nothing else has to move. Measurement ids are per body, not per iteration, so the program’s measurement registry is unaffected too.

Templates are pooled and shared, so every instance of template changes with it. That is usually the point — one cube kind, one bulk duration — but a caller that means to retune only some placements must check the sharing itself; this call cannot tell the two intents apart.

§Errors

Returns EditError::UnknownTemplate for an id outside the pool, and EditError::TemplateNotSingleLooped when the template’s entry body has anything other than exactly one top-level REPEAT — with zero there is no loop to retune, and with several the call would silently mean “all of them”.

§Panics

Panics only if a template disappears after it is read from the pool.

Source

pub fn insert_memory_rounds_batch( &mut self, targets: &[MemoryRoundTarget], rounds: u32, ) -> Result<Vec<BloqNodeId>, EditError>

Insert memory rounds at every target or at none, returning node ids in target order. Targets may mix edges and terminal nodes at any level. An empty target list is a no-op, but zero rounds is always rejected.

§Errors

Returns EditError if membership is unresolved, any target or seam is invalid, or rounds is zero. Any error leaves self unchanged.

Editing a clone and swapping on success costs one clone for the whole batch, where looping over the public Bloq::insert_memory_rounds would clone once per target and leave the earlier targets padded when a later one fails. Targets are applied in order. A duplicate or overlapping target that becomes invalid also rolls back the whole batch.

Source

pub fn subdivide_quantum_edge( &mut self, from: BloqNodeId, to: BloqNodeId, padding: &[PaddingInstance], rounds: u32, ) -> Result<BloqNodeId, EditError>

Splice padding into from -> to, producing from -> padding -> to.

Before mutation, this allocates fresh instance ids and verifies the original stored seam entries before recomposing both replacement halves. Partial seams leaving a merge may move closures between nodes and retarget output-face operators; full-node seams preserve side-table entries one-for-one. rounds is recorded as memory-padding provenance on the new node.

Returns the new padding node id. Re-resolve node ids held across this call because vacant slots may be recycled.

§Errors

Returns EditError when the seam, padding instances, or stored detector composition is invalid.

Source§

impl Bloq

Source

pub fn flatten(&mut self) -> Result<(), FlattenError>

Flatten every repeat block in the program (see the module docs): each template an instance references is flattened once via BloqTemplate::flatten (flattened copies are appended to the pool — it is append-only — and instances re-pointed), expanding repeat-scoped detectors into per-iteration detectors and clearing all loop-carried detector state. Instance-space side tables (node detectors, observable record reads, boundary operators) stay valid untouched because final occurrences keep their measurement ids.

Verify-before-apply: all templates are flattened and all checks run before any instance is re-pointed, so the program is unmodified on error. Decoder-wait insertion after flattening splices looped padding templates again; flatten again afterwards if needed.

§Errors

See FlattenError.

Source

pub fn flatten_with_limits( &mut self, limits: FlattenLimits, ) -> Result<(), FlattenError>

Self::flatten with a cumulative allowance across all distinct referenced templates and their side tables. Repeated instances share one flattened template; an exhausted allowance leaves the Bloq intact.

§Errors

Returns FlattenError for invalid references or exhausted cumulative work; self remains unchanged.

Source§

impl Bloq

Source

pub fn node_detector_count( &self, node: &QuantumNode, ) -> Result<usize, DetectorBundleError>

Count inline and bound detector rows after checking local bundle structure.

§Errors

Returns a DetectorBundleError for a missing bundle, invalid binding, invalid local owner slot, or a count/address overflow.

Source

pub fn check_detector_bundle_bindings( &self, node: &QuantumNode, lookup: impl FnMut(TemplateInstanceId) -> Option<TemplateId>, ) -> Result<(), DetectorBundleError>

Check every bundle owner binding against a caller’s instance registry.

§Errors

Returns local structure errors from Self::node_detector_count, or DetectorBundleError::UnknownBoundInstance / DetectorBundleError::OwnerTemplateMismatch when the supplied registry does not match a bundle’s owner signature.

Source

pub fn node_detectors<'a>( &'a self, node: &'a QuantumNode, ) -> Result<NodeDetectors<'a>, DetectorBundleError>

Borrow node detectors in inline, bundle-use, and bundle-row order.

§Errors

Returns the same structural errors as Self::node_detector_count.

Source§

impl Bloq

Source

pub fn set_logical_inputs(&mut self, inputs: Vec<LogicalInput>)

Replace the logical-input metadata.

Source

pub fn logical_inputs(&self) -> &[LogicalInput]

Logical input patches in deterministic source-port order.

Source

pub fn output_frames(&self) -> Vec<FramePair>

The per-output terminal Pauli-frame signs: one FramePair per source output port, in (x, y, z) order. Derived from the NodeProvenance::OutputFrame stamps on frame-sign Compute nodes — the stamps are the single source of truth, so this table cannot drift from the graph. Validation guarantees every stamped output carries exactly one X and one Z stamp; on an unvalidated program an incomplete pair is skipped.

Source

pub fn set_logical_outputs(&mut self, outputs: Vec<LogicalOutput>)

Replace the terminal logical-output metadata.

Source

pub fn logical_outputs(&self) -> &[LogicalOutput]

Terminal logical operators in deterministic output order.

Source§

impl Bloq

Source

pub fn new() -> Self

Create an empty program.

Source

pub fn top(&self) -> &SubGraph

The top graph level. Region bodies are further SubGraph levels, reached through crate::RegionNode::bodies or Bloq::levels.

Source

pub fn top_mut(&mut self) -> &mut SubGraph

Mutable top graph level.

This invalidates derived layout data because arbitrary graph edits may change the program’s qubit footprint.

Source

pub fn metadata(&self) -> &BTreeMap<String, MetadataValue>

Producer-specific provenance, keyed by a namespaced stable name.

Source

pub fn insert_metadata( &mut self, key: impl Into<String>, value: impl Into<MetadataValue>, ) -> Option<MetadataValue>

Insert producer metadata, returning the previous value for key.

Source

pub fn pipe_padding(&self) -> impl Iterator<Item = &PipePadding>

Every edge-owned memory-padding record in the program.

Source

pub fn add_template(&mut self, template: BloqTemplate) -> TemplateId

Add an owned template and return its id.

§Panics

Panics before insertion if the next template id exceeds u32.

Source

pub fn add_shared_template(&mut self, template: Arc<BloqTemplate>) -> TemplateId

Add a shared template and return its id.

§Panics

Panics before insertion if the next template id exceeds u32.

Source

pub fn templates(&self) -> &BloqTemplatePool

Program template pool.

Source

pub fn detector_bundles(&self) -> &DetectorBundlePool

Reusable detector bundle pool.

Source

pub fn add_detector_bundle( &mut self, bundle: DetectorBundle, ) -> DetectorBundleId

Add owned detector rows to the shared bundle pool.

§Panics

Panics before insertion if the next bundle id exceeds u32.

Source

pub fn add_shared_detector_bundle( &mut self, bundle: Arc<DetectorBundle>, ) -> DetectorBundleId

Import an immutable shared detector bundle.

§Panics

Panics before insertion if the next bundle id exceeds u32.

Source

pub fn add_node(&mut self, node: BloqNode) -> BloqNodeId

Add a top-level node and return its id.

Source

pub fn add_edge(&mut self, from: BloqNodeId, to: BloqNodeId, edge: BloqEdge)

Adds a top-level edge; panics on a stale endpoint id, like SubGraph::add_edge.

Source

pub fn node_mut(&mut self, id: BloqNodeId) -> Option<&mut BloqNode>

Mutable top-level node lookup.

Source

pub fn remove_node(&mut self, id: BloqNodeId) -> Option<BloqNode>

Remove a top-level node and its incident edges.

Source

pub fn quantum_node_count(&self) -> usize

The number of top-level quantum nodes. Unlike Self::node_count this excludes the classical Observable nodes, so it stays a stable measure of lowered blocks for perf tracking.

Source

pub fn qubit_count(&self) -> Result<usize, CoordinateOverflowError>

The number of distinct physical qubit coordinates in the layout.

§Errors

Returns CoordinateOverflowError if translating an instance qubit exceeds the coordinate lattice.

Source

pub fn sorted_layout_coords(&self) -> Result<&[IVec2], CoordinateOverflowError>

The program’s distinct layout qubit coordinates, sorted by (x, y). Computed once and cached; the cache is cleared on any mutation.

§Errors

Returns CoordinateOverflowError if an instance offset would move a template qubit outside the i32 coordinate lattice.

Source

pub fn node_qubits( &self, node: &BloqNode, ) -> Result<FxHashSet<IVec2>, CoordinateOverflowError>

The layout qubits a node occupies: each instance’s template qubits translated by the instance offset. Instances pointing at a missing template are skipped.

§Errors

Returns CoordinateOverflowError if an instance offset would move a template qubit outside the i32 coordinate lattice.

Source

pub fn node_measurement_count(&self, node: &BloqNode) -> usize

The number of static measurement sites in a node and its nested bodies. RUS bodies contribute; this is not a runtime execution count.

Source

pub fn measurement_count(&self) -> usize

The number of static measurement sites in the program.

Source§

impl Bloq

Source

pub fn node(&self, id: BloqNodeId) -> Option<&BloqNode>

The top level’s SubGraph::node. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn node_ids(&self) -> impl DoubleEndedIterator<Item = BloqNodeId> + '_

The top level’s SubGraph::node_ids. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn nodes( &self, ) -> impl DoubleEndedIterator<Item = (BloqNodeId, &BloqNode)> + '_

The top level’s SubGraph::nodes. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn quantum_nodes( &self, ) -> impl Iterator<Item = (BloqNodeId, &QuantumNode)> + '_

The top level’s SubGraph::quantum_nodes. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn node_count(&self) -> usize

The top level’s SubGraph::node_count. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn edge_count(&self) -> usize

The top level’s SubGraph::edge_count. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn edges(&self) -> impl Iterator<Item = BloqEdgeRef<'_>> + '_

The top level’s SubGraph::edges. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn incoming( &self, id: BloqNodeId, ) -> impl Iterator<Item = BloqEdgeRef<'_>> + '_

The top level’s SubGraph::incoming. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn outgoing( &self, id: BloqNodeId, ) -> impl Iterator<Item = BloqEdgeRef<'_>> + '_

The top level’s SubGraph::outgoing. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn edges_between( &self, from: BloqNodeId, to: BloqNodeId, ) -> impl Iterator<Item = BloqEdgeRef<'_>> + '_

The top level’s SubGraph::edges_between. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn has_path(&self, from: BloqNodeId, to: BloqNodeId) -> bool

The top level’s SubGraph::has_path. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn path_scratch(&self) -> PathScratch

The top level’s SubGraph::path_scratch. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn has_path_with_scratch( &self, from: BloqNodeId, to: BloqNodeId, scratch: &mut PathScratch, ) -> bool

The top level’s SubGraph::has_path_with_scratch. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn value_inputs( &self, id: BloqNodeId, ) -> impl Iterator<Item = ValueInput<'_>> + '_

The top level’s SubGraph::value_inputs. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn data_inputs( &self, id: BloqNodeId, ) -> impl Iterator<Item = ValueInput<'_>> + '_

The top level’s SubGraph::data_inputs. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn data_consumers( &self, id: BloqNodeId, ) -> impl Iterator<Item = (BloqNodeId, u32)> + '_

The top level’s SubGraph::data_consumers. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn compose_consumers( &self, id: BloqNodeId, ) -> impl Iterator<Item = (BloqNodeId, u32)> + '_

The top level’s SubGraph::compose_consumers. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn value_consumers( &self, id: BloqNodeId, ) -> impl Iterator<Item = (BloqNodeId, u32)> + '_

The top level’s SubGraph::value_consumers. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn open_value_producers(&self) -> impl Iterator<Item = BloqNodeId> + '_

The top level’s SubGraph::open_value_producers. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn open_bit_producers(&self) -> impl Iterator<Item = BloqNodeId> + '_

The top level’s SubGraph::open_bit_producers. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn value_output(&self) -> Option<ValueRef>

The top level’s SubGraph::value_output. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn boundary_outputs(&self) -> &[BloqNodeId]

The top level’s SubGraph::boundary_outputs. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn is_acyclic(&self) -> bool

The top level’s SubGraph::is_acyclic. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source

pub fn is_acyclic_with_edges(&self, extra: &[(BloqNodeId, BloqNodeId)]) -> bool

The top level’s SubGraph::is_acyclic_with_edges. Region body levels are reached through Bloq::levels / Bloq::level_at.

Source§

impl Bloq

Source

pub fn deterministic_emit_order(&self) -> Result<Vec<BloqNodeId>, CycleDetected>

The top level’s deterministic topological emission order.

§Errors

Returns CycleDetected if the top-level graph contains a cycle.

Source§

impl Bloq

Source

pub fn stable_key_map( &self, ) -> Result<BTreeMap<NodeKey, BloqNodeId>, CycleDetected>

The top level’s stable keys as a lookup table, for resolving a key obtained from another program into a node id in this one.

§Errors

Returns CycleDetected when the program has no emit order.

Source§

impl Bloq

Source

pub fn optimize(&mut self) -> Result<(), CycleDetected>

Fuse computations and compatible observable recipes, then keep only the contributor frontier of observable ordering dependencies per level. Acyclicity is checked before any rewrite.

§Errors

Returns CycleDetected without rewriting anything if any level has a cycle.

Source§

impl Bloq

Source

pub fn pin_membership( &self, choices: &BTreeMap<String, bool>, ) -> Result<Self, MembershipPinError>

Pin named structural branches and selective-measurement outcomes. The returned program retains selected instance ids, record aliases, and signed flow recipes. Guards implied by the joint choices are removed; unresolved predicates and RUS retries retain their runtime semantics.

Every source selector must be pinned, and the joint tuple must be consistent with its Boolean dataflow. self remains unchanged.

§Errors

Returns MembershipPinError for cyclic dataflow, missing or ambiguous choices, contradictory assignments, or malformed membership data. Call Self::validate explicitly to audit all IR well-formedness rules.

Source

pub fn has_conditional_membership(&self) -> bool

Whether quantum stages, seams, or quantum-containing region activations have conditional membership. Static emission and slicing require selection; timing and memory edits also support exhaustive terminal choices. Classical activation only gates a recipe; it does not change membership.

Source§

impl Bloq

Source

pub fn regions_of(&self, kind: RegionKind) -> Vec<RegionRef>

Every region node of kind, at every nesting level.

Ordered by Bloq::levels: levels pre-order top-down, ascending node id within a level. Filter on RegionRef::path being top-level when only the outermost regions matter.

Source

pub fn selection_seams( &self, ) -> Result<Vec<(BloqNodeId, BloqNodeId)>, StructureError>

The quantum seams each top-level guarded component waits on, as (source, selection) pairs in ascending selection-node-id order.

Subdividing those edges (Bloq::insert_memory_rounds_batch) delays the component until its guard inputs are ready. Within one component, seams are ordered by source node id. This query does not certify that an unresolved selection supports scheduling or memory edits.

§Errors

Returns StructureError::SelectionInputMissing if a guarded component has no incoming quantum edge.

Source

pub fn node_by_block(&self, pos: IVec3) -> Option<BloqNodeId>

The top-level node realizing source block pos, or None when no node carries it.

Lowering partitions the source blocks across NodeProvenance::BlockComponent nodes, so at most one node can match — this is a lookup, not a search with a preferred answer.

Source§

impl Bloq

Source

pub fn resolve_classical( &self, node: BloqNodeId, assignment: ClassicalAssignment<'_>, ) -> Result<ClassicalResolution, ResolveError>

The physical-measurement and decoder-flip recipe behind a top-level classical node’s value, folded under a fixed path.

Follows the node’s Value inputs recursively, descending into a region under assignment and out through that body’s declared bit result (SEM-RVAL). Observable fragments and complete observables contribute measurements; Const leaves contribute sign. An observable also contributes its named decoder flip on its Corrected output; composition includes only its recipe.

§Errors

Returns ResolveError when the path does not determine a region or nonlinear cofactor, or when the fold reaches a node with no static value (a quantum node or a Discard).

Source

pub fn resolve_value( &self, value: ValueRef, assignment: ClassicalAssignment<'_>, ) -> Result<ClassicalResolution, ResolveError>

Resolve a selected runtime output under a fixed path.

§Errors

Returns the same errors as Self::resolve_classical.

Source

pub fn measurement_dependencies( &self, node: BloqNodeId, assignment: ClassicalAssignment<'_>, ) -> Result<BTreeSet<InstanceMeasurement>, ResolveError>

Which measurement records node’s value waits on, rather than what parity it is.

Unlike the parity fold, this conservatively unions all record dependencies, including records needed for Flip outputs and nonlinear expressions.

§Errors

Returns the same errors as Self::resolve_classical.

Source

pub fn measurement_value_dependencies( &self, value: ValueRef, assignment: ClassicalAssignment<'_>, ) -> Result<BTreeSet<InstanceMeasurement>, ResolveError>

Measurement dependencies of a selected runtime output, including Flip.

§Errors

Returns the same errors as Self::measurement_dependencies.

Source

pub fn classical_value( &self, node: BloqNodeId, assignment: ClassicalAssignment<'_>, ) -> Result<bool, ResolveError>

The bit a top-level node already takes on a fixed path.

Where Self::resolve_classical answers which measurements a value is assembled from, this answers what that value is — for the nodes a path determines offline, with no per-shot record involved. A Observable reads its corrected bit from the path’s forced_observables, and a Compute folds its own expression over those leaves.

Under ClassicalAssignment::Uniform every predicate leaf folds to the uniform bit, matching how a uniform path fixes predicate inputs.

§Errors

Returns ResolveError when the node is quantum, when it is a RepeatUntilSuccess region (whose restart predicate is per-attempt decoder state, not a path constant), or when the fold reaches a node the path does not fix — a fragment’s per-shot record, or an observable with no forced value.

Source

pub fn classical_ref_value( &self, value: ValueRef, assignment: ClassicalAssignment<'_>, ) -> Result<bool, ResolveError>

A selected output’s bit when fixed by the supplied path.

§Errors

Returns the same errors as Self::classical_value.

Source§

impl Bloq

Source

pub fn stats(&self) -> Result<BloqStats, BloqStatsError>

Inventory stored IR structure without inspecting physical circuit payloads.

Unlike Self::node_count and Self::edge_count, counts include all nested graph levels and concrete node/edge kinds. Every stored region body contributes once, independently of guards and retry attempts. Static means fixed execution structure: no regions, node activation, conditional quantum membership/seams, or shot discard. Classical computation/readout/decoding and fixed circuit repeats alone remain static. This is neither the explicit Self::validate audit nor a guarantee that a particular backend can emit the program.

§Errors

Returns BloqStatsError::CountOverflow if a structural total overflows.

Source§

impl Bloq

Source

pub fn to_text(&self) -> String

Render this program in the text exchange format (also Display).

Source

pub fn from_text(text: &str) -> Result<Self, TextParseError>

Parse a program from the text exchange format.

§Errors

Returns TextParseError for malformed syntax, unsupported versions, invalid references, or structurally invalid serialized data.

Source§

impl Bloq

Source

pub fn walk(&self, f: impl FnMut(NodeCx<'_>) -> WalkControl) -> WalkControl

Pre-order depth-first walk over every node at every nesting level, in ascending node-id order within a level (the validation/scan order — use SubGraph::deterministic_emit_order per level when you need the schedule). Returns WalkControl::Stop if the callback stopped the walk, else WalkControl::Continue.

The callback receives a NodeCx for each visited node and returns a WalkControl: Continue to descend into the node’s region bodies (if any), SkipBodies to visit the node but prune its bodies, or Stop to abort the whole walk.

§Examples

In real code a Bloq comes from the compiler (bloq_compile), but that crate depends on this one, so — to keep this doctest free of a dependency cycle — we parse an equivalent program from the .bloqir text format instead. It is a single quantum node feeding a RepeatUntilSuccess region (whose body holds another quantum node and an observable fragment), then a terminal observable — the shape a magic-state (T) block lowers to.

use bloq_ir::{Bloq, BloqNodeKind, WalkControl};

let program = Bloq::from_text(
    "\
BLOQIR 1

template t0 {
  circuit {
    MPP X(0,0):m0
  }
}

graph {
  n0 quantum {
    instance i0 t0 @ (0,0)
  }
  n1 rus in0 source n0 {
    body {
      n0 quantum {
        instance i1 t0 @ (2,0)
      }
      n1 observable fragment measurements i1:m0 from generator 0
      n0 -> n1 order
    }
  }
  n2 observable 0
  n0 -> n1 order
  n1 -> n2 order
}
",
)
.expect("valid .bloqir text");

// A full walk visits every node at every level, matching on kind.
let (mut quantum, mut classical, mut region) = (0, 0, 0);
program.walk(|cx| {
    match cx.node.kind {
        BloqNodeKind::Quantum(_) => quantum += 1,
        BloqNodeKind::Classical(_) => classical += 1,
        BloqNodeKind::Region(_) => region += 1,
    }
    WalkControl::Continue
});
// Two quantum (top-level + in-body), two classical (in-body fragment +
// terminal observable), one region.
assert_eq!((quantum, classical, region), (2, 2, 1));

// `SkipBodies` prunes region bodies: the two in-body nodes are skipped,
// leaving only the three top-level nodes.
let mut top_level = 0;
program.walk(|cx| {
    top_level += 1;
    match cx.node.kind {
        BloqNodeKind::Region(_) => WalkControl::SkipBodies,
        _ => WalkControl::Continue,
    }
});
assert_eq!(top_level, 3);

// `Stop` aborts early. Here we halt at the first region and report it.
let mut region_path = None;
let control = program.walk(|cx| {
    if matches!(cx.node.kind, BloqNodeKind::Region(_)) {
        region_path = Some(cx.path.clone());
        WalkControl::Stop
    } else {
        WalkControl::Continue
    }
});
assert_eq!(control, WalkControl::Stop);
// The region is at the top level, so its owner path is empty.
assert!(region_path.expect("stopped at the region").segments().is_empty());
Source

pub fn levels(&self) -> impl Iterator<Item = (LevelPath, &SubGraph)>

Every graph level, pre-order top-down: the top level, then each region body. For whole-program table passes (instance collection, id allocation) that read levels rather than individual nodes.

Each item is (LevelPath, &SubGraph): the path identifies the level (empty for the top level), and the SubGraph exposes the level’s full read surface — nodes, edges, deterministic_emit_order, etc.

§Examples

A per-level table pass that sums quantum nodes across the whole program (see Bloq::walk for the .bloqir program used here):

use bloq_ir::{Bloq, BloqNodeKind};

let mut level_count = 0;
let mut quantum_total = 0;
for (path, level) in program.levels() {
    level_count += 1;
    let quantum = level
        .nodes()
        .filter(|(_, node)| matches!(node.kind, BloqNodeKind::Quantum(_)))
        .count();
    quantum_total += quantum;
    // `path` is the level's identity: empty at the top, one hop inside
    // the region body.
    assert!(path.segments().len() <= 1);
}
// Two levels (top + the region body), one quantum node in each.
assert_eq!(level_count, 2);
assert_eq!(quantum_total, 2);
Source

pub fn level_at(&self, path: &LevelPath) -> Option<&SubGraph>

The graph level identified by path, or None if a hop is stale or names the wrong region body.

Source§

impl Bloq

Source

pub fn validate(&self) -> Result<(), BloqValidationError>

Validates IR well-formedness, including nested region bodies.

Same-layer qubit overlap depends on source BlockGraph soft corridors and is checked by bloq_compile lowering.

WF-9 checks every reachable selected merge. Self::validate_with_plans additionally returns static plans and certified conditional stages. This entry point releases each merged circuit after checking its node, bounding temporary circuit storage by the largest quantum stage. Within one noiseless validation, successful unguarded merges are reused at the same relative placements; absolute coordinates are still checked.

§Errors

Returns BloqValidationError for any violated IR well-formedness or bounded-resource rule.

Source

pub fn validate_with_options( &self, options: &InstantiationOptions<'_>, ) -> Result<(), BloqValidationError>

Validate with explicit noise and resource limits, releasing emission plans after each node instead of retaining them.

§Errors

Returns BloqValidationError for invalid IR, merge, noise, or exhausted resources.

Source

pub fn validate_with_plans( &self, options: &InstantiationOptions<'_>, ) -> Result<ValidatedPlans, BloqValidationError>

Self::validate, additionally returning static NodeEmissionPlans and certified conditional stages, keyed by scoped address (see ValidatedPlans). Plans are instantiated with options.

Applies the same well-formedness rules as Self::validate, charging work for every materialized plan. SEM-MERGE applies noise once to the post-merge circuit, and the returned plans carry the caller’s options. Conditional membership uses pairwise Boolean overlap checks. A malformed NoiseModel also changes the outcome: its probabilities are only checked while materializing noise, so a bad model surfaces here (and only under noisy options) as InvalidInstanceMergeStructure at the first quantum node.

§Errors

Returns BloqValidationError under the same conditions as Self::validate_with_options.

§Panics

Panics only if the internal plan collector is unexpectedly absent.

Source

pub fn emission_plans( &self, options: &InstantiationOptions<'_>, ) -> Result<ValidatedPlans, BloqValidationError>

Materialize static quantum stages without a full well-formedness audit. Guarded stages are marked for the consumer to select and materialize; no Boolean proof of their entire choice domain is performed here.

Required static merges and their noise application still fail here. A consumer must report failures while materializing selected guarded stages. Call Self::validate_with_plans explicitly for the complete all-choice IR audit as well as plans.

§Errors

InvalidInstanceMergeStructure if a static quantum node’s instances cannot merge (SEM-MERGE).

§Caution

This is not a substitute for Self::validate. Malformed IR outside the materialized stages may not be reported by this method.

Source§

impl Bloq

Source

pub fn to_svg(&self, include_classical: bool) -> String

Render the program dependency graph as a self-contained SVG.

include_classical includes classical nodes and their incident edges. When false, quantum nodes, regions and their direct dependencies remain. Nested region bodies are drawn inside their owning container. Quantum, composition, value and order edges retain distinct colors; this is a structural view of all alternatives, not one selected runtime execution.

let program = bloq_ir::Bloq::new();
let svg = program.to_svg(true);
assert!(svg.starts_with("<svg"));

Trait Implementations§

Source§

impl Clone for Bloq

Source§

fn clone(&self) -> Bloq

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Bloq

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Bloq

Source§

fn default() -> Bloq

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for Bloq

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Bloq

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Index<BloqNodeId> for Bloq

The panicking twin of Bloq::node (see SubGraph’s Index impl).

Source§

type Output = BloqNode

The returned type after indexing.
Source§

fn index(&self, id: BloqNodeId) -> &Self::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl Serialize for Bloq

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl !Freeze for Bloq

§

impl RefUnwindSafe for Bloq

§

impl Send for Bloq

§

impl Sync for Bloq

§

impl Unpin for Bloq

§

impl UnsafeUnpin for Bloq

§

impl UnwindSafe for Bloq

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T, BorrowedSelf> BitwiseMutViaBorrow<BorrowedSelf> for T
where T: BorrowMut<BorrowedSelf>, BorrowedSelf: BitwiseMut + ?Sized,

§

fn assign_index(&mut self, index: usize, to: bool)

§

fn negate_index(&mut self, index: usize)

§

fn clear_bits(&mut self)

§

fn assign_random( &mut self, bit_count: usize, random_number_generator: &mut impl RngExt, )
where BorrowedSelf: BitLength,

§

impl<Bits, Other, BorrowedSelf, BorrowedOther> BitwisePairMutViaBorrow<Other, BorrowedSelf, BorrowedOther> for Bits
where Bits: BorrowMut<BorrowedSelf> + ?Sized, Other: Borrow<BorrowedOther> + ?Sized, BorrowedSelf: Bitwise + BitwisePairMut<BorrowedOther> + ?Sized, BorrowedOther: Bitwise + ?Sized,

§

fn assign(&mut self, other: &Other)

§

fn bitxor_assign(&mut self, other: &Other)

§

fn bitand_assign(&mut self, other: &Other)

§

fn bitor_assign(&mut self, other: &Other)

§

impl<T, Other, BorrowedSelf, BorrowedOther> BitwisePairViaBorrow<Other, BorrowedSelf, BorrowedOther> for T
where T: Borrow<BorrowedSelf> + ?Sized, Other: Borrow<BorrowedOther> + ?Sized, BorrowedSelf: Bitwise + BitwisePair<BorrowedOther> + ?Sized, BorrowedOther: Bitwise + ?Sized,

§

fn dot(&self, other: &Other) -> bool

§

fn and_weight(&self, other: &Other) -> usize

§

fn or_weight(&self, other: &Other) -> usize

§

fn xor_weight(&self, other: &Other) -> usize

§

impl<T, BorrowedSelf> BitwiseViaBorrow<BorrowedSelf> for T
where T: Borrow<BorrowedSelf>, BorrowedSelf: Bitwise + ?Sized,

§

fn index(&self, index: usize) -> bool

§

fn weight(&self) -> usize

§

fn parity(&self) -> bool

§

fn is_zero(&self) -> bool

§

fn is_unit(&self, index: usize) -> bool

§

fn support<'a>(&'a self) -> impl SortedIterator
where BorrowedSelf: 'a,

§

fn max_support(&self) -> Option<usize>

§

fn min_support(&self) -> Option<usize>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.