Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
e6f3a5f
Document and fix from_guppy DEM handoff.
ciaranra May 21, 2026
368681e
Merge branch 'dev' into from-guppy-dem-handoff
ciaranra May 27, 2026
20f549b
Enable generic Selene runtime plugins in PECOS.
ciaranra May 29, 2026
e9b1a0b
Rename observable-subgraph decoder to logical-subgraph, add >64-obser…
ciaranra May 29, 2026
a2e18fa
Preserve runtime idle gates through QEC DEM generation.
ciaranra May 30, 2026
cc3c4ba
Merge guppy runtime tracing into from-guppy DEM handoff.
ciaranra May 30, 2026
c2cbfe1
Allow traced Guppy DEMs to use custom Selene runtimes.
ciaranra May 30, 2026
85cdcfa
Keep runtime plugin handoff wording generic.
ciaranra May 30, 2026
0962b20
Add weighted Pauli DEM noise support
ciaranra May 31, 2026
1a99447
Support runtime-remapped surface DEM metadata
ciaranra May 31, 2026
bdb8509
Replace logical-subgraph byte-level DEM parser with shared line-based…
ciaranra May 31, 2026
1288e6e
Rename test locals lsd_* to subgraph_* to avoid clash with BP-LSD acr…
ciaranra May 31, 2026
3095ed3
Count logical_observable declarations in DEM parsers so unflipped obs…
ciaranra May 31, 2026
dae55dc
Split logical-subgraph membership source from subgraph extractor and …
ciaranra May 31, 2026
96f95df
Reject non-flattened DEMs (repeat / shift_detectors) in line-based pa…
ciaranra May 31, 2026
6fd2ce4
Add LogicalSubgraphDecoder.from_membership and compare coordinate vs …
ciaranra May 31, 2026
6235775
Support replacement two-qubit DEM weights
ciaranra May 31, 2026
454a60c
Add back-prop-seeded group-fill region comparison: strictly broader t…
ciaranra May 31, 2026
8835879
Add branch-impact DEM approximation
ciaranra May 31, 2026
1c28615
Default LogicalSubgraphDecoder inner to pecos_uf:bp (exact-MWPM LER, …
ciaranra May 31, 2026
51acac9
Reserve exact replacement branch replay
ciaranra May 31, 2026
5fff680
Start exact branch replay plumbing
ciaranra May 31, 2026
de1ed63
Attach exact branch replay context
ciaranra May 31, 2026
78a21a5
Validate omitted branch replay locations
ciaranra May 31, 2026
5e96dc9
Validate exact branch effects
ciaranra May 31, 2026
b923f17
Emit exact replacement branch effects
ciaranra May 31, 2026
b30b093
Guard LogicalSubgraphDecoder distance suppression (xfail-strict): doc…
ciaranra May 31, 2026
7030f56
Thread exact branch context through surface DEMs
ciaranra May 31, 2026
e90ba04
Document exact branch replay surface DEMs
ciaranra May 31, 2026
fc48370
Fix LogicalSubgraphDecoder distance suppression: default to exact-MWP…
ciaranra May 31, 2026
1cd1e2f
Speed up exact branch DEM replay
ciaranra Jun 1, 2026
b2b5273
Fix UF predecoder to fall through for non-provably-optimal isolated/p…
ciaranra Jun 4, 2026
54456c2
Rewrite windowed logical-subgraph decoder to correct sliding-window c…
ciaranra Jun 4, 2026
8730617
Add shared coord-preserving LogicalSubgraphWindowPlan and make the lo…
ciaranra Jun 5, 2026
a671a33
Unify standalone WindowedLogicalSubgraphDecoder onto the shared Logic…
ciaranra Jun 5, 2026
ca52fd6
Address deep review: fix WindowedLogicalSubgraphStrategy to flip the …
ciaranra Jun 6, 2026
90125b9
Second-review hygiene: harden parse_dem_metadata (max+1 observable co…
ciaranra Jun 6, 2026
66f377f
Fix 3 Codex-review blockers: emit real physical code distance in the …
ciaranra Jun 7, 2026
03d4d02
Prototype reliable_observables: derive decodable logical-observable c…
ciaranra Jun 7, 2026
76554b3
Preserve runtime result provenance for traced surface DEMs
ciaranra Jun 7, 2026
3fd9942
Default LogicalSubgraphDecoder inner to fusion_blossom_serial (exact …
ciaranra Jun 7, 2026
7d1244a
Reuse constructor inner decoder in LogicalSubgraphDecoder.decode_coun…
ciaranra Jun 7, 2026
c90c883
Fix constrained ancilla DAG propagation
ciaranra Jun 8, 2026
d397665
Add powered inner-decoder threshold/LER study establishing fusion_blo…
ciaranra Jun 8, 2026
4c5a546
Add hyperedge-regime phase closing the threshold study's graphlike ca…
ciaranra Jun 8, 2026
6da12ff
Tighten surface DEM result handling
ciaranra Jun 10, 2026
16d4596
Preserve runtime surface DEM metadata through traced QIS
ciaranra Jun 10, 2026
b50419b
Expose measurement crosstalk noise bindings
ciaranra Jun 11, 2026
5c4c388
Document measurement crosstalk DEM semantics
ciaranra Jun 11, 2026
6c1caf7
Add exact deterministic local crosstalk DEM support
ciaranra Jun 11, 2026
96425bb
Expose measurement crosstalk DEM options to Python
ciaranra Jun 11, 2026
e20eeaf
Fail loudly for crosstalk DEMs without payloads
ciaranra Jun 11, 2026
4424532
Expose crosstalk payload gate types to Python
ciaranra Jun 11, 2026
594dc8b
Preserve crosstalk payload gates in traced replay
ciaranra Jun 11, 2026
53c1074
Document noise event replay diagnostics
ciaranra Jun 11, 2026
b58771a
Add biased single-qubit DEM noise support
ciaranra Jun 12, 2026
5dcad76
Fix full-branch review findings 1-6: propagate decode_count_parallel …
ciaranra Jun 12, 2026
47c5f3d
Add stim_spotcheck phase confirming the fusion-vs-bp ranking transfer…
ciaranra Jun 12, 2026
ddbf9f9
Add sine-law idle noise support for DEM construction
ciaranra Jun 12, 2026
e023b9f
Add Guppy surface Pauli twirl handoff
ciaranra Jun 12, 2026
b8c3776
Address Pauli twirl review findings
ciaranra Jun 12, 2026
888dad2
Treat Pauli meta ticks as zero-duration
ciaranra Jun 12, 2026
0adfae6
Harden meta tick idle accounting
ciaranra Jun 12, 2026
930ad80
Polish Pauli twirl handoff lint checks
ciaranra Jun 12, 2026
1a651bf
Tighten Pauli twirl canonicalization tests
ciaranra Jun 12, 2026
17276d2
Strengthen Guppy Pauli twirl validation
ciaranra Jun 12, 2026
9eccee9
Add gate-local Guppy Pauli twirl schedule
ciaranra Jun 12, 2026
96e4313
Add gate-local twirl mask variation guard
ciaranra Jun 12, 2026
b8414f4
Add scaled Guppy Pauli twirl activation
ciaranra Jun 12, 2026
faf8ece
Add SZZ surface interaction basis skeleton
ciaranra Jun 12, 2026
ea0dde3
Add SZZ noiseless detector equivalence
ciaranra Jun 12, 2026
8ebc302
Tighten SZZ residual metadata
ciaranra Jun 13, 2026
38297bb
Add SZZ Guppy surface basis
ciaranra Jun 13, 2026
4e09ba8
Tighten SZZ Guppy review coverage
ciaranra Jun 13, 2026
71d6aad
Add SZZ forward-flow pulse guard
ciaranra Jun 13, 2026
63f1903
Guard SZZ surface DEM pulse noise
ciaranra Jun 13, 2026
67d90e7
Add SZZ gate-specific noise rates
ciaranra Jun 13, 2026
e7e3030
Add SZZ prefix p1 lowering
ciaranra Jun 13, 2026
a624ce1
Tighten SZZ prefix DEM coverage
ciaranra Jun 13, 2026
b83ddc1
Enable SZZ idle prefix lowering
ciaranra Jun 13, 2026
f97c148
Tighten SZZ idle prefix guards
ciaranra Jun 13, 2026
ea742f8
Expose surface interaction basis selection
ciaranra Jun 13, 2026
09291ba
Fix traced SZZ DEM validation and raw sampler routing
ciaranra Jun 13, 2026
04e5cfe
Expose correlated PyMatching DEM option
ciaranra Jun 13, 2026
c722969
Add DEM decomposition diagnostics
ciaranra Jun 13, 2026
cba0f05
Add two-fault DEM decomposition diagnostics
ciaranra Jun 13, 2026
c64e79b
Add terminal graphlike DEM projection
ciaranra Jun 13, 2026
6cbbadb
Add graphlike DEM diagnostic filters
ciaranra Jun 13, 2026
fc8db92
Add graphlike DEM projection benchmark
ciaranra Jun 13, 2026
c3d2f76
Add deterministic measurement crosstalk DEM replay mode
ciaranra Jun 13, 2026
cd7edf4
Add surface interaction quality report
ciaranra Jun 13, 2026
dedd7ab
Align SZZ frame gate noise accounting
ciaranra Jun 13, 2026
3bf2e7b
Simplify traced Clifford gate chains
ciaranra Jun 13, 2026
0f6a41b
Support averaged global measurement crosstalk DEM replay
ciaranra Jun 13, 2026
d7c3055
Document SZZ DEM modeling assumptions
ciaranra Jun 13, 2026
1f41d5b
Merge cliff-def-handoff-twirl into DEM handoff integration
ciaranra Jun 13, 2026
bd0b1cc
Align Guppy DEM reference normalization
ciaranra Jun 13, 2026
63328dd
Report DEM diagnostic progress and partial results
ciaranra Jun 13, 2026
f727699
Add surface sweep JSON comparison tool
ciaranra Jun 13, 2026
e01005e
Improve graphlike surface decoder validation
ciaranra Jun 14, 2026
76af0d3
Make DEM diagnostics resumable from saved results
ciaranra Jun 14, 2026
6df15f1
Add surface check plan metadata
ciaranra Jun 14, 2026
379d8c0
Support MeasureFree in sim_neo extract_commands and align stale measu…
ciaranra Jun 14, 2026
fe5d68c
Normalize the fresh traced circuit in the constrained-budget cache te…
ciaranra Jun 14, 2026
9e4fceb
Restore QEC branch health checks
ciaranra Jun 14, 2026
930d4f0
Thread check plan metadata through topology cache
ciaranra Jun 14, 2026
848c1ee
Merge remote-tracking branch 'origin/cliff-def-handoff-twirl' into in…
ciaranra Jun 14, 2026
4a7220c
Merge remote-tracking branch 'origin/decoder-polish' into integrate-c…
ciaranra Jun 14, 2026
659f996
Clean decoder study report whitespace
ciaranra Jun 14, 2026
3a63c1e
Harden parser/binding robustness: SparseDem rejects malformed D/L tok…
ciaranra Jun 15, 2026
a0af8f8
Address residual review nits: reject boundary-gate observable bits >=…
ciaranra Jun 15, 2026
7e63b2f
Handle Selene runtime capacity after merged runtime changes.
ciaranra Jun 15, 2026
846d818
Merge remote-tracking branch 'origin/decoder-polish' into integrate-c…
ciaranra Jun 15, 2026
088671d
Add logical decoder descriptor validation regressions.
ciaranra Jun 15, 2026
ceaccc9
Respect explicit QIS physical qubit capacity.
ciaranra Jun 15, 2026
0b6b925
Support constrained SZZ surface memory circuits.
ciaranra Jun 15, 2026
b104276
Thread check plans through Guppy surface generation
ciaranra Jun 15, 2026
e9df730
Require check plans to match current surface renderers
ciaranra Jun 16, 2026
5692adf
Accept check plans in direct surface builders
ciaranra Jun 16, 2026
984bc04
Add boundary-first SZZ surface check plan
ciaranra Jun 16, 2026
dba699f
Use trace-friendly backend for Guppy operation capture
ciaranra Jun 16, 2026
7934d1a
Test trace-friendly Guppy operation capture
ciaranra Jun 16, 2026
ba9f4c9
Add uniform Clifford frame SZZ DEM plumbing
ciaranra Jun 17, 2026
3ada9b1
Support traced SZZ Clifford-frame surface programs
ciaranra Jun 17, 2026
6edc487
Support checkerboard Clifford surface frames
ciaranra Jun 18, 2026
5dfc8b6
Cover both checkerboard surface frame orientations
ciaranra Jun 18, 2026
e9a7d7a
Add balanced surface ancilla scheduling
ciaranra Jun 22, 2026
099c6d3
Forward-flow SZZ Guppy data frames within helpers
ciaranra Jun 23, 2026
0f94310
Add optional SZZ runtime barriers
ciaranra Jun 23, 2026
dc1dfe4
Add selective SZZ runtime barrier policy
ciaranra Jun 23, 2026
16e3515
Add generic trace metadata plumbing for QIS replay
ciaranra Jun 25, 2026
38fb253
Add SZZ source metadata plumbing
ciaranra Jun 25, 2026
eda0cd8
Preserve qubit-scoped SZZ trace metadata
ciaranra Jun 25, 2026
3210d0b
Fence SZZ prefixes before runtime barriers
ciaranra Jun 25, 2026
a1abbd1
Document Guppy barrier trace gap
ciaranra Jun 25, 2026
88ee9b1
Add hosted operation design note
ciaranra Jun 25, 2026
f8495a6
Add hosted SZZ metadata keys
ciaranra Jun 25, 2026
51f0aca
Add hosted operation metadata validation
ciaranra Jun 26, 2026
568ed65
Add strict hosted trace validation plumbing
ciaranra Jun 26, 2026
43a33bd
Add hosted SZZ barrier handoff target
ciaranra Jun 26, 2026
514463c
Add runtime barrier helper for SZZ traces
ciaranra Jun 27, 2026
e5b889c
Reject ambiguous hosted operation metadata
ciaranra Jun 27, 2026
cb868f5
Scope SZZ hosted metadata by counted round
ciaranra Jun 27, 2026
b103696
Use physical SZZ hosted prefixes in Guppy
ciaranra Jun 28, 2026
969ade0
Allow SZZ Guppy builds without trace metadata
ciaranra Jun 28, 2026
f4dbff6
Use two-qubit runtime barrier for SZZ hosted prefixes
ciaranra Jun 28, 2026
5187e74
Use native Selene runtime barriers
ciaranra Jun 28, 2026
124aa4c
Pack generated SZZ trace metadata
ciaranra Jun 28, 2026
11c6fd2
Pin balanced batch-order touch-gap optimum
ciaranra Jun 30, 2026
1554207
Pin balanced round-order touch-gap tradeoffs
ciaranra Jun 30, 2026
67ce2d7
Add SZZ round-order check plan
ciaranra Jun 30, 2026
cf8fe47
Gate round-order renderer metadata
ciaranra Jun 30, 2026
dbc967c
Gate round-order SZZ DEM equivalence
ciaranra Jun 30, 2026
f5c902c
Gate round-order noiseless SZZ records
ciaranra Jun 30, 2026
e71a914
Add 1032 round-order surface schedule
ciaranra Jul 1, 2026
cf6e958
Merge origin/dev into PECOS integration branch
ciaranra Jul 7, 2026
af85f9d
Fix PECOS dev merge integration issues
ciaranra Jul 7, 2026
79d2885
Merge branch 'dev' into pecos-dev-merge
ciaranra Jul 8, 2026
e389f69
Merge branch 'dev' into pecos-dev-merge
ciaranra Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 47 additions & 122 deletions crates/pecos-decoder-core/src/logical_algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

use crate::ObservableDecoder;
use crate::errors::DecoderError;
use crate::obs_mask::ObsMask;

/// One segment of a logical algorithm.
pub struct SegmentDescriptor {
Expand Down Expand Up @@ -175,18 +174,15 @@ impl LogicalAlgorithmDecoder {

/// Apply boundary gate to a Pauli frame.
/// Used when consuming the frame at logical operations.
///
/// # Errors
/// Returns [`DecoderError::ObservableBitOutOfRange`] if any of the gate's
/// observable bits is `>= 64`. All bits index the `u64` observable frame, so
/// each must be `< 64`; the Python descriptor binding rejects this at
/// construction, and this runtime check guards the same invariant for direct
/// Rust callers (a shift by `>= 64` is otherwise an overflow panic in debug /
/// unspecified in release).
pub fn apply_boundary_gate(frame: &mut u64, gate: &BoundaryGate) -> Result<(), DecoderError> {
if let Some(&bit) = gate.obs_bits().iter().find(|&&b| b >= 64) {
return Err(DecoderError::ObservableBitOutOfRange { bit });
}
pub fn apply_boundary_gate(frame: &mut u64, gate: &BoundaryGate) {
// All bits index the u64 observable frame, so each must be < 64. The
// Python descriptor binding enforces this fail-loud at construction; this
// documents and guards the invariant for direct Rust callers (a shift by
// >= 64 is otherwise an overflow panic in debug / unspecified in release).
debug_assert!(
gate.obs_bits().iter().all(|&b| b < 64),
"boundary gate observable bit >= 64"
);
match gate {
BoundaryGate::Hadamard {
x_obs_bit,
Expand Down Expand Up @@ -236,17 +232,14 @@ impl LogicalAlgorithmDecoder {
}
}
}
Ok(())
}
}

impl ObservableDecoder for LogicalAlgorithmDecoder {
fn decode_to_observables(&mut self, syndrome: &[u8]) -> Result<u64, DecoderError> {
self.decode_shot(syndrome)
}

fn decode_obs(&mut self, syndrome: &[u8]) -> Result<ObsMask, DecoderError> {
self.full_decoder.decode_obs(syndrome)
fn decode_obs(&mut self, syndrome: &[u8]) -> Result<crate::obs_mask::ObsMask, DecoderError> {
Ok(crate::obs_mask::ObsMask::from_u64(
self.decode_shot(syndrome)?,
))
}
}

Expand All @@ -267,10 +260,10 @@ impl ObservableDecoder for LogicalAlgorithmDecoder {
///
/// ```
/// use pecos_decoder_core::{DecoderError, ObservableDecoder};
/// use pecos_decoder_core::obs_mask::ObsMask;
/// use pecos_decoder_core::logical_algorithm::{
/// AlgorithmDescriptor, LogicalAlgorithmDecoder, SegmentDescriptor, StreamingLogicalDecoder,
/// };
/// use pecos_decoder_core::obs_mask::ObsMask;
///
/// struct AnyDetectionDecoder;
///
Expand Down Expand Up @@ -359,18 +352,6 @@ impl StreamingLogicalDecoder {
Ok(obs)
}

/// Wide variant of [`Self::flush`]: returns an [`ObsMask`] supporting more
/// than 64 observables (no truncation).
pub fn flush_obs(&mut self) -> Result<ObsMask, DecoderError> {
self.inner.decode_obs(&self.syndrome)
}

/// Wide variant of [`Self::decode_shot`]: feed + flush as an [`ObsMask`].
pub fn decode_shot_obs(&mut self, syndrome: &[u8]) -> Result<ObsMask, DecoderError> {
self.feed_dense(syndrome);
self.flush_obs()
}

/// Decode a full syndrome at once (convenience for batch mode).
pub fn decode_shot(&mut self, syndrome: &[u8]) -> Result<u64, DecoderError> {
self.feed_dense(syndrome);
Expand Down Expand Up @@ -402,11 +383,8 @@ impl StreamingLogicalDecoder {
}

/// Apply boundary gate to a Pauli frame (delegates to inner).
///
/// # Errors
/// Propagates [`DecoderError::ObservableBitOutOfRange`] from the inner apply.
pub fn apply_boundary_gate(frame: &mut u64, gate: &BoundaryGate) -> Result<(), DecoderError> {
LogicalAlgorithmDecoder::apply_boundary_gate(frame, gate)
pub fn apply_boundary_gate(frame: &mut u64, gate: &BoundaryGate) {
LogicalAlgorithmDecoder::apply_boundary_gate(frame, gate);
}

/// Reset for the next shot.
Expand Down Expand Up @@ -601,15 +579,10 @@ impl LogicalCircuitDecoder {
}

impl ObservableDecoder for LogicalCircuitDecoder {
fn decode_to_observables(&mut self, syndrome: &[u8]) -> Result<u64, DecoderError> {
self.decode_shot(syndrome)
}

fn decode_obs(&mut self, syndrome: &[u8]) -> Result<ObsMask, DecoderError> {
self.reset();
let len = syndrome.len().min(self.total_detectors);
self.syndrome[..len].copy_from_slice(&syndrome[..len]);
self.strategy.decode_obs(&self.syndrome)
fn decode_obs(&mut self, syndrome: &[u8]) -> Result<crate::obs_mask::ObsMask, DecoderError> {
Ok(crate::obs_mask::ObsMask::from_u64(
self.decode_shot(syndrome)?,
))
}
}

Expand Down Expand Up @@ -639,10 +612,6 @@ impl DecodeStrategy for FullCircuitStrategy {
self.inner.decode_to_observables(syndrome)
}

fn decode_obs(&mut self, syndrome: &[u8]) -> Result<ObsMask, DecoderError> {
self.inner.decode_obs(syndrome)
}

fn commit(&mut self, _region: &DetectorRegion) -> Result<u64, DecoderError> {
// Full circuit doesn't commit incrementally
Ok(0)
Expand Down Expand Up @@ -717,6 +686,13 @@ impl WindowedLogicalSubgraphStrategy {
observable_indices.len(),
)));
}
if let Some(&bad) = observable_indices.iter().find(|&&o| o >= 64) {
return Err(DecoderError::InvalidConfiguration(format!(
"WindowedLogicalSubgraphStrategy: observable index {bad} >= 64 \
exceeds the u64 observable-mask capacity"
)));
}

let mut decoders = Vec::with_capacity(num);
let mut sub_syndromes = Vec::with_capacity(num);
for (i, dem_str) in subgraph_dems.iter().enumerate() {
Expand All @@ -736,17 +712,8 @@ impl WindowedLogicalSubgraphStrategy {
}

impl DecodeStrategy for WindowedLogicalSubgraphStrategy {
/// Narrowing wrapper over [`Self::decode_obs`]; errors above 64 observables.
fn decode(&mut self, syndrome: &[u8]) -> Result<u64, DecoderError> {
self.decode_obs(syndrome)?.to_u64().ok_or_else(|| {
DecoderError::InvalidConfiguration(
"decoder has more than 64 observables; use decode_obs() for the wide mask".into(),
)
})
}

fn decode_obs(&mut self, syndrome: &[u8]) -> Result<ObsMask, DecoderError> {
let mut obs_mask = ObsMask::new();
let mut obs_mask = 0u64;

for (i, (dec, dmap)) in self
.subgraph_decoders
Expand Down Expand Up @@ -774,7 +741,7 @@ impl DecodeStrategy for WindowedLogicalSubgraphStrategy {
// position `i`, which differs once empty observables are filtered).
let sub_obs = dec.decode_to_observables(&buf[..n])?;
if sub_obs & 1 != 0 {
obs_mask.set(self.observable_indices[i]);
obs_mask |= 1u64 << self.observable_indices[i];
}
}

Expand Down Expand Up @@ -835,7 +802,7 @@ mod tests {
// regions and were filtered out. Each reports its observable as local
// bit 0; the strategy must flip the GLOBAL bit, not the list position.
// (The pre-fix `1 << i` would have produced bits {0,1} = 0b0011.)
let mut strategy = WindowedLogicalSubgraphStrategy::new(
let mut strat = WindowedLogicalSubgraphStrategy::new(
vec![
"error(0.1) D0 L0".to_string(),
"error(0.1) D0 L0".to_string(),
Expand All @@ -845,27 +812,19 @@ mod tests {
|_dem| Ok(Box::new(FixedDecoder(1)) as Box<dyn ObservableDecoder + Send + Sync>),
)
.unwrap();
let obs = strategy.decode(&[1, 1]).unwrap();
let obs = strat.decode(&[1, 1]).unwrap();
assert_eq!(obs, (1u64 << 1) | (1u64 << 3));
}

#[test]
fn windowed_strategy_supports_observable_index_over_63() {
use crate::decode_budget::DecodeStrategy;
// Observable index 64 was previously rejected; it now constructs and the
// wide `decode_obs` represents bit 64 with no truncation.
let mut s = WindowedLogicalSubgraphStrategy::new(
fn windowed_strategy_rejects_observable_index_over_63() {
let r = WindowedLogicalSubgraphStrategy::new(
vec!["error(0.1) D0 L0".to_string()],
vec![vec![0usize]],
vec![64usize],
|_dem| Ok(Box::new(FixedDecoder(1)) as Box<dyn ObservableDecoder + Send + Sync>),
)
.unwrap();
let wide = s.decode_obs(&[1]).unwrap();
assert!(wide.get(64));
assert_eq!(wide.to_u64(), None);
// The narrowing u64 path errors rather than truncating.
assert!(s.decode(&[1]).is_err());
);
assert!(r.is_err());
}

#[test]
Expand All @@ -888,31 +847,8 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
assert_eq!(frame, 0b10); // X became Z
}

#[test]
fn test_apply_boundary_gate_rejects_obs_bit_ge_64() {
// A boundary bit >= 64 cannot index the u64 frame; apply must fail loud
// (not panic in debug / shift-overflow in release) for direct Rust callers.
let mut frame = 0u64;
let result = LogicalAlgorithmDecoder::apply_boundary_gate(
&mut frame,
&BoundaryGate::Hadamard {
x_obs_bit: 64,
z_obs_bit: 1,
},
);
assert!(matches!(
result,
Err(DecoderError::ObservableBitOutOfRange { bit: 64 })
));
assert_eq!(
frame, 0,
"frame must be untouched when the gate is rejected"
);
assert_eq!(frame, 0b10); // X became Z
}

#[test]
Expand Down Expand Up @@ -966,8 +902,7 @@ mod tests {
tgt_x_bit: 2,
tgt_z_bit: 3,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b0101); // X propagated to target
}

Expand Down Expand Up @@ -1011,8 +946,7 @@ mod tests {
tgt_x_bit: 2,
tgt_z_bit: 3,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b1010); // Z propagated back to control Z (bit 1)
}

Expand All @@ -1028,8 +962,7 @@ mod tests {
tgt_x_bit: 2,
tgt_z_bit: 3,
},
)
.expect("boundary observable bits < 64");
);
// X ctrl -> X tgt (bit 2), Z tgt -> Z ctrl (bit 1)
assert_eq!(frame, 0b1111);
}
Expand All @@ -1044,8 +977,7 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b11); // X stays, Z also set
}

Expand All @@ -1059,8 +991,7 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b10); // Z stays, no X induced
}

Expand All @@ -1073,8 +1004,7 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0); // No correction, no change
}

Expand All @@ -1088,8 +1018,7 @@ mod tests {
z_obs_bit: 1, // data Z
ancilla_z_bit: 3, // ancilla Z
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b1010); // data Z (bit 1) flipped
}

Expand All @@ -1103,8 +1032,7 @@ mod tests {
z_obs_bit: 1,
ancilla_z_bit: 3,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b1000); // data Z cancelled, ancilla unchanged
}

Expand All @@ -1118,8 +1046,7 @@ mod tests {
z_obs_bit: 1,
ancilla_z_bit: 3,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b0010); // unchanged
}

Expand All @@ -1133,8 +1060,7 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b11); // Swap of (1,1) is still (1,1)
}

Expand All @@ -1147,8 +1073,7 @@ mod tests {
x_obs_bit: 0,
z_obs_bit: 1,
},
)
.expect("boundary observable bits < 64");
);
assert_eq!(frame, 0b01); // Z became X
}

Expand Down
Loading
Loading