1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/*
* SPDX-License-Identifier: MIT
* Copyright (c) 2023 - 2026. The DeepCausality Authors and Contributors. All Rights Reserved.
*/
use alloc::format;
use alloc::string::String;
use core::fmt::{Debug, Display, Formatter};
use deep_causality_core::{CausalityError, CausalityErrorEnum};
/// The crate-local quantum error: an outer newtype over [`QuantumErrorEnum`],
/// mirroring the repo convention (`CausalityError(CausalityErrorEnum::…)`).
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuantumError(pub QuantumErrorEnum);
/// Detailed classification of quantum errors. Typed variants name the exact
/// failure; a `String` payload carries the operation-specific context.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum QuantumErrorEnum {
/// Operations attempted on states or operators with incompatible dimensions/shapes.
DimensionMismatch(String),
/// The operands carry different Clifford metric signatures.
MetricMismatch(String),
/// The Clifford metric is unsupported for the requested operation
/// (e.g. an odd-dimensional metric for the ket↔matrix bridge), or a
/// metric convention error surfaced from `deep_causality_metric`.
UnsupportedMetric(String),
/// A non-finite value (NaN, ±inf) was produced or encountered.
NonFiniteValue(String),
/// Probability normalization failed (value < 0, > 1, or sum ≠ 1).
NormalizationError(String),
/// An operator required to be positive (semi-)definite is not.
NonPositiveOperator(String),
/// A density or Choi–Jamiołkowski operator does not have the required trace.
NonUnitTrace(String),
/// A channel is not completely positive and trace-preserving.
NonCptpChannel(String),
/// A partial trace was requested with an inconsistent subsystem shape.
PartialTraceShape(String),
/// The freeze-time quantum Markov check found a non-commuting factor pair;
/// `node_j`/`node_k` name the offending operators by graph node index.
CommutatorNonZero {
node_j: usize,
node_k: usize,
detail: String,
},
/// The declared causal structure contains a `C₃` sub-relation and therefore
/// does not imply a unitary causally faithful decomposition in the
/// traditional circuit paradigm (van der Lugt & Lorenz, arXiv:2508.11762,
/// Definition 3.1 and Theorem 3.2).
///
/// "Faithfully" is the Lorenz–Barrett sense: a circuit decomposition whose
/// connectivity equals the unitary's causal structure, `G_U = G_C`. It is not
/// Pearl's faithfulness, where a distribution has no independences beyond
/// those its graph implies. The structure is what is rejected; a particular
/// unitary with that structure may still decompose faithfully (Remark 3.3),
/// and every such unitary has a routed decomposition.
NotFaithfullyRepresentable(String),
/// A Markov re-check on a composite's *inherited* factors found a
/// non-commuting pair. This is a failure of the certificate, not of the
/// model: Barrett–Lorenz–Oreshkov's representation theorem gives every
/// composite of QCM-representable parts a Markov factorization for the
/// induced DAG with the induced factors, and the naive product of the
/// parts' factors need not be it. `CommutatorNonZero` is reserved for
/// factors that are the model's own.
CertificateNotInherited {
node_j: usize,
node_k: usize,
detail: String,
},
/// A structural candidate's causal structure contains a directed cycle.
/// Cyclic quantum causal models exist (Barrett, Lorenz & Oreshkov,
/// arXiv:2002.12157) and the C₃ criterion does not reject them, so this is
/// a scope decision made at `build()`, before any check runs, and it names
/// the limit rather than an obstruction.
CyclicStructureUnsupported(String),
/// `design` was asked to cover more hypotheses than its cap. The exact
/// cover is a dynamic program over `2^C(n,2)` subsets of pairs: `2^15` at
/// n = 6, `2^28` at n = 8, `2^45` at n = 10. Above `max_hypotheses` the
/// solve is refused before the table is allocated, naming `n` and the
/// pair count. A later version may supply the greedy cover with its
/// logarithmic approximation factor reported; v1 does not.
HypothesisCountExceeded { n: usize, pairs: usize },
/// A marginalisation was refused because its boundary warrant did not
/// hold: the kept-factor operator `Z ⊗ 1_B` fails to commute with the
/// operator being traced within the named tolerance, so nothing may be
/// asserted about the traced commutator and no traced operator is
/// produced. The message carries the residual, the tolerance and the
/// amplification; `Hypothesis::boundary_warrant` returns them typed.
BoundaryNotHeld(String),
/// A Pauli handed to the logical-equivalence predicate lies outside the
/// code's normalizer: it anticommutes with the stabilizer generator named by
/// `generator`, so it does not preserve the code space and the question of
/// whether it acts trivially there is not well-posed. `detail` says which
/// kind of generator, `Z` or `X`.
NotInNormalizer { generator: usize, detail: String },
/// A gate in a program handed to the Clifford tableau is not Clifford, so
/// its conjugation action on a Pauli is not a symplectic update and the
/// program cannot be pushed through. Names the gate and its position.
NonCliffordGate(String),
/// An abstraction constructor was handed a process operator without its
/// circuit. A bare `ProcessFactors` store is the marginal of a compositional
/// model and not one itself (Lorenz & Tull, arXiv:2602.16612, Example 62),
/// so it validates as in v1 and cannot enter an abstraction. Carries the subject's origin.
NoCompositionalModel { origin: String },
/// The numeric semantics would form a composite Choi operator of
/// `2^(2n + 2k)` entries above its cap: `n` and `k` are the input and output
/// qubit counts (rounded up from the dimensions), `entries` the count it
/// would allocate, `cap` the limit. Refused before allocating.
NaturalityDimensionExceeded {
n: usize,
k: usize,
entries: u64,
cap: u64,
},
/// The numeric semantics would carry a Kraus family (the product of the
/// operator counts of every noise box and measurement outcome) above its cap.
/// Refused before allocating.
KrausFamilyExceeded { operators: u64, cap: u64 },
/// A fault was asked to propagate through a program with no normal form of
/// polynomial size: two non-Clifford layers separated by a non-diagonal
/// Clifford. `layer` is the non-diagonal Clifford layer and `after` the
/// non-Clifford layer whose remainder precedes it. The propagator refuses
/// rather than expanding.
NoPropagationNormalForm { layer: usize, after: usize },
/// An interchange query named sets that are not parallelisable: the directed
/// path `from → to` joins two members of interchange set `set` (Lorenz &
/// Tull §7.2).
NotParallelisable { set: usize, from: usize, to: usize },
/// A type alignment's section does not invert its channel: for alignment
/// entry `entry`, `‖τ_X ∘ E_X − id‖_F` exceeds the state tolerance; `detail`
/// states the residual and the tolerance.
SectionNotInverse { entry: usize, detail: String },
/// Numerical conversion or general calculation failure.
CalculationError(String),
}
impl QuantumError {
pub(crate) fn new(variant: QuantumErrorEnum) -> Self {
Self(variant)
}
#[allow(non_snake_case)]
pub fn DimensionMismatch(msg: String) -> Self {
Self(QuantumErrorEnum::DimensionMismatch(msg))
}
#[allow(non_snake_case)]
pub fn MetricMismatch(msg: String) -> Self {
Self(QuantumErrorEnum::MetricMismatch(msg))
}
#[allow(non_snake_case)]
pub fn UnsupportedMetric(msg: String) -> Self {
Self(QuantumErrorEnum::UnsupportedMetric(msg))
}
#[allow(non_snake_case)]
pub fn NonFiniteValue(msg: String) -> Self {
Self(QuantumErrorEnum::NonFiniteValue(msg))
}
#[allow(non_snake_case)]
pub fn NormalizationError(msg: String) -> Self {
Self(QuantumErrorEnum::NormalizationError(msg))
}
#[allow(non_snake_case)]
pub fn NonPositiveOperator(msg: String) -> Self {
Self(QuantumErrorEnum::NonPositiveOperator(msg))
}
#[allow(non_snake_case)]
pub fn NonUnitTrace(msg: String) -> Self {
Self(QuantumErrorEnum::NonUnitTrace(msg))
}
#[allow(non_snake_case)]
pub fn NonCptpChannel(msg: String) -> Self {
Self(QuantumErrorEnum::NonCptpChannel(msg))
}
#[allow(non_snake_case)]
pub fn PartialTraceShape(msg: String) -> Self {
Self(QuantumErrorEnum::PartialTraceShape(msg))
}
#[allow(non_snake_case)]
pub fn CommutatorNonZero(node_j: usize, node_k: usize, detail: String) -> Self {
Self(QuantumErrorEnum::CommutatorNonZero {
node_j,
node_k,
detail,
})
}
#[allow(non_snake_case)]
pub fn NotFaithfullyRepresentable(msg: String) -> Self {
Self(QuantumErrorEnum::NotFaithfullyRepresentable(msg))
}
#[allow(non_snake_case)]
pub fn CertificateNotInherited(node_j: usize, node_k: usize, detail: String) -> Self {
Self(QuantumErrorEnum::CertificateNotInherited {
node_j,
node_k,
detail,
})
}
#[allow(non_snake_case)]
pub fn CyclicStructureUnsupported(msg: String) -> Self {
Self(QuantumErrorEnum::CyclicStructureUnsupported(msg))
}
#[allow(non_snake_case)]
pub fn HypothesisCountExceeded(n: usize, pairs: usize) -> Self {
Self(QuantumErrorEnum::HypothesisCountExceeded { n, pairs })
}
#[allow(non_snake_case)]
pub fn BoundaryNotHeld(msg: String) -> Self {
Self(QuantumErrorEnum::BoundaryNotHeld(msg))
}
#[allow(non_snake_case)]
pub fn NotInNormalizer(generator: usize, detail: String) -> Self {
Self(QuantumErrorEnum::NotInNormalizer { generator, detail })
}
#[allow(non_snake_case)]
pub fn NonCliffordGate(msg: String) -> Self {
Self(QuantumErrorEnum::NonCliffordGate(msg))
}
#[allow(non_snake_case)]
pub fn NoCompositionalModel(origin: String) -> Self {
Self(QuantumErrorEnum::NoCompositionalModel { origin })
}
#[allow(non_snake_case)]
pub fn NaturalityDimensionExceeded(n: usize, k: usize, entries: u64, cap: u64) -> Self {
Self(QuantumErrorEnum::NaturalityDimensionExceeded { n, k, entries, cap })
}
#[allow(non_snake_case)]
pub fn KrausFamilyExceeded(operators: u64, cap: u64) -> Self {
Self(QuantumErrorEnum::KrausFamilyExceeded { operators, cap })
}
#[allow(non_snake_case)]
pub fn NoPropagationNormalForm(layer: usize, after: usize) -> Self {
Self(QuantumErrorEnum::NoPropagationNormalForm { layer, after })
}
#[allow(non_snake_case)]
pub fn NotParallelisable(set: usize, from: usize, to: usize) -> Self {
Self(QuantumErrorEnum::NotParallelisable { set, from, to })
}
#[allow(non_snake_case)]
pub fn SectionNotInverse(entry: usize, detail: String) -> Self {
Self(QuantumErrorEnum::SectionNotInverse { entry, detail })
}
#[allow(non_snake_case)]
pub fn CalculationError(msg: String) -> Self {
Self(QuantumErrorEnum::CalculationError(msg))
}
}
// Integration with the generic CausalityError, mirroring the physics crate.
impl From<QuantumError> for CausalityError {
fn from(e: QuantumError) -> Self {
CausalityError::new(CausalityErrorEnum::Custom(format!("{}", e)))
}
}
impl From<deep_causality_metric::MetricError> for QuantumError {
fn from(e: deep_causality_metric::MetricError) -> Self {
QuantumError::new(QuantumErrorEnum::UnsupportedMetric(format!("{}", e)))
}
}
impl core::error::Error for QuantumError {}
impl Display for QuantumError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match &self.0 {
QuantumErrorEnum::DimensionMismatch(msg) => write!(f, "Dimension Mismatch: {}", msg),
QuantumErrorEnum::MetricMismatch(msg) => write!(f, "Metric Mismatch: {}", msg),
QuantumErrorEnum::UnsupportedMetric(msg) => write!(f, "Unsupported Metric: {}", msg),
QuantumErrorEnum::NonFiniteValue(msg) => write!(f, "Non-Finite Value: {}", msg),
QuantumErrorEnum::NormalizationError(msg) => {
write!(f, "Normalization Error: {}", msg)
}
QuantumErrorEnum::NonPositiveOperator(msg) => {
write!(f, "Non-Positive Operator: {}", msg)
}
QuantumErrorEnum::NonUnitTrace(msg) => write!(f, "Non-Unit Trace: {}", msg),
QuantumErrorEnum::NonCptpChannel(msg) => write!(f, "Non-CPTP Channel: {}", msg),
QuantumErrorEnum::PartialTraceShape(msg) => {
write!(f, "Partial Trace Shape Error: {}", msg)
}
QuantumErrorEnum::CommutatorNonZero {
node_j,
node_k,
detail,
} => write!(
f,
"Non-Zero Commutator: factors at nodes {} and {} do not commute: {}",
node_j, node_k, detail
),
QuantumErrorEnum::NotFaithfullyRepresentable(msg) => {
write!(f, "Not Faithfully Representable (C3 obstruction): {}", msg)
}
QuantumErrorEnum::CertificateNotInherited {
node_j,
node_k,
detail,
} => write!(
f,
"Certificate Not Inherited: the parts' factors at nodes {} and {} do not certify the composite: {}",
node_j, node_k, detail
),
QuantumErrorEnum::CyclicStructureUnsupported(msg) => {
write!(f, "Cyclic Structure Unsupported: {}", msg)
}
QuantumErrorEnum::HypothesisCountExceeded { n, pairs } => write!(
f,
"Hypothesis Count Exceeded: {} hypotheses give {} pairs, above the design cap",
n, pairs
),
QuantumErrorEnum::BoundaryNotHeld(msg) => write!(f, "Boundary Not Held: {}", msg),
QuantumErrorEnum::NotInNormalizer { generator, detail } => write!(
f,
"Not In Normalizer: anticommutes with stabilizer generator {} ({})",
generator, detail
),
QuantumErrorEnum::NonCliffordGate(msg) => write!(f, "Non-Clifford Gate: {}", msg),
QuantumErrorEnum::NoCompositionalModel { origin } => write!(
f,
"No Compositional Model: a {} subject is the marginal of a compositional model and not one itself; only a circuit subject, whose dilation carries the model, can enter an abstraction",
origin
),
QuantumErrorEnum::NaturalityDimensionExceeded { n, k, entries, cap } => write!(
f,
"Naturality Dimension Exceeded: a channel from {} to {} qubits has a composite Choi of {} entries, above the cap of {}",
n, k, entries, cap
),
QuantumErrorEnum::KrausFamilyExceeded { operators, cap } => write!(
f,
"Kraus Family Exceeded: {} operators, above the cap of {}",
operators, cap
),
QuantumErrorEnum::NoPropagationNormalForm { layer, after } => write!(
f,
"No Propagation Normal Form: layer {} is a non-diagonal Clifford layer following the non-Clifford remainder left by layer {}; the propagated error is neither a Pauli nor diagonal and has no normal form of polynomial size",
layer, after
),
QuantumErrorEnum::NotParallelisable { set, from, to } => write!(
f,
"Not Parallelisable: interchange set {} holds nodes {} and {}, joined by the directed path {} → {}",
set, from, to, from, to
),
QuantumErrorEnum::SectionNotInverse { entry, detail } => {
write!(f, "Section Not Inverse: entry {}: {}", entry, detail)
}
QuantumErrorEnum::CalculationError(msg) => write!(f, "Calculation Error: {}", msg),
}
}
}