Skip to main content

bloq_circuit/
error.rs

1use glam::IVec2;
2use thiserror::Error;
3
4use crate::{BodyId, GateType, LoopStateId};
5
6/// A coordinate plus layout offset does not fit the signed 32-bit lattice.
7#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
8#[error("translating coordinate {coordinate:?} by {offset:?} overflows i32")]
9pub struct CoordinateOverflowError {
10    /// Coordinate before translation.
11    pub coordinate: IVec2,
12    /// Requested translation offset.
13    pub offset: IVec2,
14}
15
16/// A failure while matching stabilizer flows across chunk boundaries.
17#[derive(Debug, Error, Clone, PartialEq, Eq)]
18pub enum FlowError {
19    /// Translating a flow boundary overflowed the coordinate lattice.
20    #[error("{0}")]
21    CoordinateOverflow(#[from] CoordinateOverflowError),
22    /// Flow boundaries could not be composed consistently.
23    #[error("{0}")]
24    Composition(String),
25}
26
27/// An overflow or out-of-range condition while accounting for the
28/// measurements a repeated (`REPEAT`) circuit body contributes.
29#[derive(Debug, Error, Clone, PartialEq, Eq)]
30pub enum MeasurementFrameError {
31    /// One operation contains more measurement records than the backend count can address.
32    #[error("operation measurement count {measurements} exceeds the u32 record range")]
33    MeasurementCountOutOfRange {
34        /// Measurement records carried by one operation.
35        measurements: usize,
36    },
37    /// One repeated block contributes too many measurements.
38    #[error(
39        "repeat frame with {measurements_per_iteration} measurements per iteration repeated {repetitions} times overflows the emitted measurement count"
40    )]
41    RepeatedMeasurementCountOverflow {
42        /// Measurements emitted by one iteration.
43        measurements_per_iteration: u32,
44        /// Number of loop iterations.
45        repetitions: u32,
46    },
47    /// Adding measurements to the emitted count overflowed.
48    #[error(
49        "emitted measurement count {emitted_count} plus repeated contribution {additional} overflows the emitted measurement count"
50    )]
51    EmittedMeasurementCountOverflow {
52        /// Count before the addition.
53        emitted_count: u32,
54        /// Measurements being added.
55        additional: u32,
56    },
57    /// A loop-body measurement offset lies outside one iteration.
58    #[error(
59        "repeat body measurement offset {offset} is outside measurements per iteration {measurements_per_iteration}"
60    )]
61    RepeatMeasurementOffsetOutOfRange {
62        /// Invalid body-local offset.
63        offset: u32,
64        /// Measurements emitted by one iteration.
65        measurements_per_iteration: u32,
66    },
67    /// Computing a loop-body measurement offset overflowed.
68    #[error("repeat body measurement offset overflowed")]
69    RepeatMeasurementOffsetOverflow,
70    /// A Stim record lookback exceeds its encoded range.
71    #[error("measurement record lookback {lookback} exceeds backend limit {max}")]
72    RecordLookbackOutOfRange {
73        /// Requested positive lookback distance.
74        lookback: u32,
75        /// Largest supported distance.
76        max: u32,
77    },
78}
79
80/// An error building, validating, or lowering a [`CoordCircuit`].
81///
82/// [`CoordCircuit`]: crate::CoordCircuit
83#[derive(Debug, Error, Clone, PartialEq, Eq)]
84pub enum CircuitError {
85    /// A measurement id is absent from the circuit registry.
86    #[error("measurement id {0} is not allocated in this circuit")]
87    InvalidMeasurementId(u32),
88    /// A circuit body id is absent.
89    #[error("invalid circuit body id {0:?}")]
90    InvalidCircuitBody(BodyId),
91    /// A circuit body index cannot be represented by a body id.
92    #[error("circuit body index {index} exceeds the u32 body-id range")]
93    BodyIdOutOfRange {
94        /// Index of the body being addressed.
95        index: usize,
96    },
97    /// A loop detector state id is absent.
98    #[error("invalid loop detector state id {0:?}")]
99    InvalidLoopDetectorState(LoopStateId),
100    /// A coordinate is absent from the output layout.
101    #[error("qubit at {0} not found in layout")]
102    QubitNotFoundInLayout(IVec2),
103    /// A qubit index is outside the output layout.
104    #[error("qubit index {index} is outside a {num_qubits}-qubit layout")]
105    QubitIndexOutOfRange {
106        /// Invalid qubit index.
107        index: usize,
108        /// Layout size.
109        num_qubits: usize,
110    },
111    /// Measurement-frame accounting failed.
112    #[error("{0}")]
113    MeasurementFrame(#[from] MeasurementFrameError),
114    /// A paired gate received an odd number of targets.
115    #[error("{gate} requires paired targets, got {targets}")]
116    InvalidGateTargetCount {
117        /// Gate being applied.
118        gate: GateType,
119        /// Supplied target count.
120        targets: usize,
121    },
122    /// An MPP operation contains no non-identity target.
123    #[error("MPP product must have at least one non-identity Pauli target")]
124    EmptyPauliProduct,
125    /// Repeat expansion exceeds the measurement-id space.
126    #[error("flattening repeat blocks would overflow the u32 measurement id space")]
127    FlattenMeasurementIdOverflow,
128    /// The expanded operation stream, targets, or replay events exceed the
129    /// caller's work allowance. `observed` saturates if the estimate overflows.
130    #[error("flattening requires at least {observed} work units (limit {limit})")]
131    FlattenResourceLimit {
132        /// Required or observed work.
133        observed: usize,
134        /// Configured work limit.
135        limit: usize,
136    },
137}