use std::time::Instant;
#[derive(Debug, Clone, PartialEq)]
pub struct StabilizerMeasurement {
pub x: u32,
pub y: u32,
pub round: u32,
pub value: bool,
}
#[derive(Debug, Clone)]
pub struct SyndromeData {
pub stabilizers: Vec<StabilizerMeasurement>,
pub code_distance: u32,
pub num_rounds: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PauliType {
X,
Z,
}
#[derive(Debug, Clone)]
pub struct Correction {
pub pauli_corrections: Vec<(u32, PauliType)>,
pub logical_outcome: bool,
pub confidence: f64,
pub decode_time_ns: u64,
}
pub trait SurfaceCodeDecoder: Send + Sync {
fn decode(&self, syndrome: &SyndromeData) -> Correction;
fn name(&self) -> &str;
}
#[derive(Debug, Clone)]
struct UnionFind {
parent: Vec<usize>,
rank: Vec<usize>,
parity: Vec<bool>,
}
impl UnionFind {
fn new(n: usize) -> Self {
Self {
parent: (0..n).collect(),
rank: vec![0; n],
parity: vec![false; n],
}
}
fn find(&mut self, mut x: usize) -> usize {
while self.parent[x] != x {
let next = self.parent[x];
self.parent[x] = self.parent[next];
x = next;
}
x
}
fn union(&mut self, a: usize, b: usize) {
let ra = self.find(a);
let rb = self.find(b);
if ra == rb {
return;
}
let (big, small) = if self.rank[ra] >= self.rank[rb] {
(ra, rb)
} else {
(rb, ra)
};
self.parent[small] = big;
self.parity[big] = self.parity[big] ^ self.parity[small];
if self.rank[big] == self.rank[small] {
self.rank[big] += 1;
}
}
fn set_parity(&mut self, node: usize, is_defect: bool) {
let root = self.find(node);
self.parity[root] = self.parity[root] ^ is_defect;
}
fn cluster_parity(&mut self, node: usize) -> bool {
let root = self.find(node);
self.parity[root]
}
}
#[derive(Debug, Clone)]
struct Defect {
x: u32,
y: u32,
round: u32,
node_index: usize,
}
pub struct UnionFindDecoder {
max_growth_radius: u32,
}
impl UnionFindDecoder {
pub fn new(max_growth_radius: u32) -> Self {
Self { max_growth_radius }
}
fn extract_defects(&self, syndrome: &SyndromeData) -> Vec<Defect> {
let d = syndrome.code_distance;
let num_rounds = syndrome.num_rounds;
let grid_w = if d > 1 { d - 1 } else { 1 };
let grid_h = if d > 1 { d - 1 } else { 1 };
let grid_size = (grid_w * grid_h * num_rounds) as usize;
let mut grid = vec![false; grid_size];
for s in &syndrome.stabilizers {
if s.x < grid_w && s.y < grid_h && s.round < num_rounds {
let idx = (s.round * grid_w * grid_h + s.y * grid_w + s.x) as usize;
if idx < grid.len() {
grid[idx] = s.value;
}
}
}
let mut defects = Vec::new();
let mut node_idx = 0usize;
for r in 0..num_rounds {
for y in 0..grid_h {
for x in 0..grid_w {
let curr_idx = (r * grid_w * grid_h + y * grid_w + x) as usize;
let curr = grid[curr_idx];
let prev = if r > 0 {
let prev_idx =
((r - 1) * grid_w * grid_h + y * grid_w + x) as usize;
grid[prev_idx]
} else {
false
};
if curr != prev {
defects.push(Defect {
x,
y,
round: r,
node_index: node_idx,
});
}
node_idx += 1;
}
}
}
defects
}
fn manhattan_distance(a: &Defect, b: &Defect) -> u32 {
let dx = (a.x as i64 - b.x as i64).unsigned_abs() as u32;
let dy = (a.y as i64 - b.y as i64).unsigned_abs() as u32;
let dr = (a.round as i64 - b.round as i64).unsigned_abs() as u32;
dx + dy + dr
}
fn boundary_distance(defect: &Defect, code_distance: u32) -> u32 {
let grid_w = if code_distance > 1 {
code_distance - 1
} else {
1
};
let grid_h = if code_distance > 1 {
code_distance - 1
} else {
1
};
let dx_min = defect.x.min(grid_w.saturating_sub(1).saturating_sub(defect.x));
let dy_min = defect.y.min(grid_h.saturating_sub(1).saturating_sub(defect.y));
dx_min.min(dy_min)
}
fn grow_and_merge(
&self,
defects: &[Defect],
total_nodes: usize,
code_distance: u32,
) -> UnionFind {
let mut uf = UnionFind::new(total_nodes);
for d in defects {
uf.set_parity(d.node_index, true);
}
if defects.is_empty() {
return uf;
}
let max_radius = if self.max_growth_radius > 0 {
self.max_growth_radius
} else {
code_distance
};
for radius in 1..=max_radius {
let mut merged_any = false;
for i in 0..defects.len() {
if !uf.cluster_parity(defects[i].node_index) {
continue; }
for j in (i + 1)..defects.len() {
if !uf.cluster_parity(defects[j].node_index) {
continue;
}
if Self::manhattan_distance(&defects[i], &defects[j]) <= 2 * radius {
uf.union(defects[i].node_index, defects[j].node_index);
merged_any = true;
}
}
}
if !merged_any {
break;
}
let all_even = defects
.iter()
.all(|d| !uf.cluster_parity(d.node_index));
if all_even {
break;
}
}
uf
}
fn corrections_from_clusters(
&self,
defects: &[Defect],
uf: &mut UnionFind,
code_distance: u32,
) -> Vec<(u32, PauliType)> {
let mut corrections = Vec::new();
let mut odd_roots: Vec<&Defect> = Vec::new();
for d in defects {
let root = uf.find(d.node_index);
if uf.parity[root] && root == d.node_index {
odd_roots.push(d);
}
}
for defect in &odd_roots {
let path = self.path_to_boundary(defect, code_distance);
corrections.extend(path);
}
let mut paired: Vec<bool> = vec![false; defects.len()];
for i in 0..defects.len() {
if paired[i] {
continue;
}
let root_i = uf.find(defects[i].node_index);
for j in (i + 1)..defects.len() {
if paired[j] {
continue;
}
let root_j = uf.find(defects[j].node_index);
if root_i == root_j && !uf.parity[root_i] {
let path = self.path_between(&defects[i], &defects[j], code_distance);
corrections.extend(path);
paired[i] = true;
paired[j] = true;
break;
}
}
}
corrections
}
fn path_to_boundary(&self, defect: &Defect, code_distance: u32) -> Vec<(u32, PauliType)> {
let mut corrections = Vec::new();
let grid_w = if code_distance > 1 {
code_distance - 1
} else {
1
};
let dist_left = defect.x;
let dist_right = grid_w.saturating_sub(defect.x + 1);
if dist_left <= dist_right {
for step in 0..=defect.x {
let data_qubit = defect.y * code_distance + (defect.x - step);
corrections.push((data_qubit, PauliType::X));
}
} else {
for step in 0..=(grid_w - defect.x - 1) {
let data_qubit = defect.y * code_distance + (defect.x + step + 1);
corrections.push((data_qubit, PauliType::X));
}
}
corrections
}
fn path_between(
&self,
a: &Defect,
b: &Defect,
code_distance: u32,
) -> Vec<(u32, PauliType)> {
let mut corrections = Vec::new();
let (mut cx, mut cy) = (a.x as i64, a.y as i64);
let (tx, ty) = (b.x as i64, b.y as i64);
while cx != tx {
let step = if tx > cx { 1i64 } else { -1 };
let data_x = if step > 0 { cx + 1 } else { cx };
let data_qubit = cy as u32 * code_distance + data_x as u32;
corrections.push((data_qubit, PauliType::X));
cx += step;
}
while cy != ty {
let step = if ty > cy { 1i64 } else { -1 };
let data_y = if step > 0 { cy + 1 } else { cy };
let data_qubit = data_y as u32 * code_distance + cx as u32;
corrections.push((data_qubit, PauliType::Z));
cy += step;
}
corrections
}
fn infer_logical_outcome(corrections: &[(u32, PauliType)]) -> bool {
let x_count = corrections
.iter()
.filter(|(_, p)| *p == PauliType::X)
.count();
x_count % 2 == 1
}
}
impl SurfaceCodeDecoder for UnionFindDecoder {
fn decode(&self, syndrome: &SyndromeData) -> Correction {
let start = Instant::now();
let defects = self.extract_defects(syndrome);
if defects.is_empty() {
let elapsed = start.elapsed().as_nanos() as u64;
return Correction {
pauli_corrections: Vec::new(),
logical_outcome: false,
confidence: 1.0,
decode_time_ns: elapsed,
};
}
let d = syndrome.code_distance;
let grid_w = if d > 1 { d - 1 } else { 1 };
let grid_h = if d > 1 { d - 1 } else { 1 };
let total_nodes = (grid_w * grid_h * syndrome.num_rounds) as usize;
let mut uf = self.grow_and_merge(&defects, total_nodes, d);
let pauli_corrections = self.corrections_from_clusters(&defects, &mut uf, d);
let logical_outcome = Self::infer_logical_outcome(&pauli_corrections);
let defect_density = defects.len() as f64 / (d as f64 * d as f64);
let confidence = (1.0 - defect_density).max(0.0).min(1.0);
let elapsed = start.elapsed().as_nanos() as u64;
Correction {
pauli_corrections,
logical_outcome,
confidence,
decode_time_ns: elapsed,
}
}
fn name(&self) -> &str {
"UnionFindDecoder"
}
}
pub struct PartitionedDecoder {
tile_size: u32,
inner_decoder: Box<dyn SurfaceCodeDecoder>,
}
impl PartitionedDecoder {
pub fn new(tile_size: u32, inner_decoder: Box<dyn SurfaceCodeDecoder>) -> Self {
assert!(tile_size > 0, "tile_size must be positive");
Self {
tile_size,
inner_decoder,
}
}
fn partition_syndrome(&self, syndrome: &SyndromeData) -> Vec<SyndromeData> {
let d = syndrome.code_distance;
let grid_w = if d > 1 { d - 1 } else { 1 };
let grid_h = if d > 1 { d - 1 } else { 1 };
let tiles_x = (grid_w + self.tile_size - 1) / self.tile_size;
let tiles_y = (grid_h + self.tile_size - 1) / self.tile_size;
let mut tiles = Vec::with_capacity((tiles_x * tiles_y) as usize);
for ty in 0..tiles_y {
for tx in 0..tiles_x {
let x_min = tx * self.tile_size;
let y_min = ty * self.tile_size;
let x_max = ((tx + 1) * self.tile_size).min(grid_w);
let y_max = ((ty + 1) * self.tile_size).min(grid_h);
let tile_w = x_max - x_min;
let tile_h = y_max - y_min;
let tile_d = tile_w.max(tile_h) + 1;
let tile_stabs: Vec<StabilizerMeasurement> = syndrome
.stabilizers
.iter()
.filter(|s| s.x >= x_min && s.x < x_max && s.y >= y_min && s.y < y_max)
.map(|s| StabilizerMeasurement {
x: s.x - x_min,
y: s.y - y_min,
round: s.round,
value: s.value,
})
.collect();
tiles.push(SyndromeData {
stabilizers: tile_stabs,
code_distance: tile_d,
num_rounds: syndrome.num_rounds,
});
}
}
tiles
}
fn merge_tile_corrections(
&self,
tile_corrections: &[Correction],
syndrome: &SyndromeData,
) -> Correction {
let d = syndrome.code_distance;
let grid_w = if d > 1 { d - 1 } else { 1 };
let tiles_x = (grid_w + self.tile_size - 1) / self.tile_size;
let mut all_corrections = Vec::new();
let mut total_confidence = 0.0;
let mut logical_outcome = false;
for (idx, tile_corr) in tile_corrections.iter().enumerate() {
let tx = idx as u32 % tiles_x;
let ty = idx as u32 / tiles_x;
let x_offset = tx * self.tile_size;
let y_offset = ty * self.tile_size;
for &(qubit, pauli) in &tile_corr.pauli_corrections {
let local_y = qubit / (d.max(1));
let local_x = qubit % (d.max(1));
let global_qubit =
(local_y + y_offset) * d + (local_x + x_offset);
all_corrections.push((global_qubit, pauli));
}
total_confidence += tile_corr.confidence;
logical_outcome ^= tile_corr.logical_outcome;
}
let avg_confidence = if tile_corrections.is_empty() {
1.0
} else {
total_confidence / tile_corrections.len() as f64
};
all_corrections.sort_by(|a, b| a.0.cmp(&b.0).then(format!("{:?}", a.1).cmp(&format!("{:?}", b.1))));
let mut deduped: Vec<(u32, PauliType)> = Vec::new();
let mut i = 0;
while i < all_corrections.len() {
let mut count = 1usize;
while i + count < all_corrections.len()
&& all_corrections[i + count].0 == all_corrections[i].0
&& all_corrections[i + count].1 == all_corrections[i].1
{
count += 1;
}
if count % 2 == 1 {
deduped.push(all_corrections[i]);
}
i += count;
}
Correction {
pauli_corrections: deduped,
logical_outcome,
confidence: avg_confidence,
decode_time_ns: 0, }
}
}
impl SurfaceCodeDecoder for PartitionedDecoder {
fn decode(&self, syndrome: &SyndromeData) -> Correction {
let start = Instant::now();
let tiles = self.partition_syndrome(syndrome);
let tile_corrections: Vec<Correction> =
tiles.iter().map(|t| self.inner_decoder.decode(t)).collect();
let mut correction = self.merge_tile_corrections(&tile_corrections, syndrome);
correction.decode_time_ns = start.elapsed().as_nanos() as u64;
correction
}
fn name(&self) -> &str {
"PartitionedDecoder"
}
}
#[derive(Debug, Clone)]
pub struct AdaptiveCodeDistance {
current_distance: u32,
min_distance: u32,
max_distance: u32,
error_history: Vec<f64>,
window_size: usize,
}
impl AdaptiveCodeDistance {
pub fn new(initial: u32, min: u32, max: u32) -> Self {
assert!(min <= max, "min_distance must be <= max_distance");
assert!(
initial >= min && initial <= max,
"initial distance must be in [min, max]"
);
let initial = if initial % 2 == 0 {
initial + 1
} else {
initial
};
Self {
current_distance: initial.min(max),
min_distance: min,
max_distance: max,
error_history: Vec::new(),
window_size: 100,
}
}
pub fn record_error_rate(&mut self, rate: f64) {
self.error_history.push(rate.clamp(0.0, 1.0));
if self.error_history.len() > self.window_size * 2 {
let drain_to = self.error_history.len() - self.window_size;
self.error_history.drain(..drain_to);
}
}
pub fn recommended_distance(&self) -> u32 {
if self.should_increase() {
let next = self.current_distance + 2; next.min(self.max_distance)
} else if self.should_decrease() {
let next = self.current_distance.saturating_sub(2);
next.max(self.min_distance)
} else {
self.current_distance
}
}
pub fn should_increase(&self) -> bool {
if self.current_distance >= self.max_distance {
return false;
}
let avg = self.average_error_rate();
if avg.is_nan() {
return false;
}
let threshold = 10.0_f64.powf(-(self.current_distance as f64) / 3.0);
avg > threshold
}
pub fn should_decrease(&self) -> bool {
if self.current_distance <= self.min_distance {
return false;
}
let avg = self.average_error_rate();
if avg.is_nan() {
return false;
}
if self.error_history.len() < self.window_size {
return false;
}
let lower_d = self.current_distance - 2;
let threshold = 10.0_f64.powf(-(lower_d as f64) / 3.0);
avg < threshold * 0.1
}
fn average_error_rate(&self) -> f64 {
if self.error_history.is_empty() {
return f64::NAN;
}
let window_start = self
.error_history
.len()
.saturating_sub(self.window_size);
let window = &self.error_history[window_start..];
let sum: f64 = window.iter().sum();
sum / window.len() as f64
}
}
#[derive(Debug, Clone)]
pub struct SurfaceCodePatch {
pub logical_id: u32,
pub physical_qubits: Vec<u32>,
pub code_distance: u32,
pub x_origin: u32,
pub y_origin: u32,
}
pub struct LogicalQubitAllocator {
total_physical: u32,
code_distance: u32,
allocated_patches: Vec<SurfaceCodePatch>,
next_logical_id: u32,
}
impl LogicalQubitAllocator {
pub fn new(total_physical: u32, code_distance: u32) -> Self {
Self {
total_physical,
code_distance,
allocated_patches: Vec::new(),
next_logical_id: 0,
}
}
pub fn max_logical_qubits(&self) -> u32 {
let d = self.code_distance as u64;
let qubits_per_logical = 2 * d * d - 2 * d + 1;
if qubits_per_logical == 0 {
return 0;
}
(self.total_physical as u64 / qubits_per_logical) as u32
}
pub fn allocate(&mut self) -> Option<SurfaceCodePatch> {
let max = self.max_logical_qubits();
if self.allocated_patches.len() as u32 >= max {
return None;
}
let d = self.code_distance;
let patch_idx = self.allocated_patches.len() as u32;
let grid_side = (self.total_physical as f64).sqrt() as u32;
let patches_per_row = if d > 0 { grid_side / d } else { 0 };
let patches_per_row = patches_per_row.max(1);
let x_origin = (patch_idx % patches_per_row) * d;
let y_origin = (patch_idx / patches_per_row) * d;
let qubits_per_logical = 2 * d * d - 2 * d + 1;
let start_qubit = patch_idx * qubits_per_logical;
let physical_qubits: Vec<u32> =
(start_qubit..start_qubit + qubits_per_logical).collect();
let logical_id = self.next_logical_id;
self.next_logical_id += 1;
let patch = SurfaceCodePatch {
logical_id,
physical_qubits,
code_distance: d,
x_origin,
y_origin,
};
self.allocated_patches.push(patch.clone());
Some(patch)
}
pub fn deallocate(&mut self, logical_id: u32) {
self.allocated_patches
.retain(|p| p.logical_id != logical_id);
}
pub fn utilization(&self) -> f64 {
let d = self.code_distance as u64;
let qubits_per_logical = 2 * d * d - 2 * d + 1;
let used = self.allocated_patches.len() as u64 * qubits_per_logical;
if self.total_physical == 0 {
return 0.0;
}
used as f64 / self.total_physical as f64
}
pub fn patches(&self) -> &[SurfaceCodePatch] {
&self.allocated_patches
}
}
#[derive(Debug, Clone)]
pub struct DecoderBenchmark {
pub total_syndromes: u64,
pub total_decode_time_ns: u64,
pub correct_corrections: u64,
pub logical_error_rate: f64,
}
impl DecoderBenchmark {
pub fn avg_decode_time_ns(&self) -> f64 {
if self.total_syndromes == 0 {
return 0.0;
}
self.total_decode_time_ns as f64 / self.total_syndromes as f64
}
pub fn throughput(&self) -> f64 {
if self.total_decode_time_ns == 0 {
return 0.0;
}
self.total_syndromes as f64 / (self.total_decode_time_ns as f64 * 1e-9)
}
}
pub fn benchmark_decoder(
decoder: &dyn SurfaceCodeDecoder,
distance: u32,
error_rate: f64,
rounds: u32,
) -> DecoderBenchmark {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let grid_w = if distance > 1 { distance - 1 } else { 1 };
let grid_h = if distance > 1 { distance - 1 } else { 1 };
let mut total_decode_time_ns = 0u64;
let mut correct_corrections = 0u64;
let mut total_syndromes = 0u64;
let mut seed: u64 = 0xDEAD_BEEF_CAFE_BABE;
let next_rand = |s: &mut u64| -> f64 {
let mut hasher = DefaultHasher::new();
s.hash(&mut hasher);
*s = hasher.finish();
(*s as f64) / (u64::MAX as f64)
};
for _ in 0..rounds {
let num_syndrome_rounds = 1u32;
let mut stabilizers = Vec::new();
let mut expected_defect_count = 0usize;
for r in 0..num_syndrome_rounds {
for y in 0..grid_h {
for x in 0..grid_w {
let val = next_rand(&mut seed) < error_rate;
if val {
expected_defect_count += 1;
}
stabilizers.push(StabilizerMeasurement {
x,
y,
round: r,
value: val,
});
}
}
}
let syndrome = SyndromeData {
stabilizers,
code_distance: distance,
num_rounds: num_syndrome_rounds,
};
let correction = decoder.decode(&syndrome);
total_decode_time_ns += correction.decode_time_ns;
total_syndromes += 1;
let expected_logical = expected_defect_count >= distance as usize;
if correction.logical_outcome == expected_logical {
correct_corrections += 1;
}
}
let logical_error_rate = if total_syndromes == 0 {
0.0
} else {
1.0 - (correct_corrections as f64 / total_syndromes as f64)
};
DecoderBenchmark {
total_syndromes,
total_decode_time_ns,
correct_corrections,
logical_error_rate,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stabilizer_measurement_creation() {
let m = StabilizerMeasurement {
x: 3,
y: 5,
round: 2,
value: true,
};
assert_eq!(m.x, 3);
assert_eq!(m.y, 5);
assert_eq!(m.round, 2);
assert!(m.value);
}
#[test]
fn test_stabilizer_measurement_clone() {
let m = StabilizerMeasurement {
x: 1,
y: 2,
round: 0,
value: false,
};
let m2 = m.clone();
assert_eq!(m, m2);
}
#[test]
fn test_syndrome_data_empty() {
let s = SyndromeData {
stabilizers: Vec::new(),
code_distance: 3,
num_rounds: 1,
};
assert!(s.stabilizers.is_empty());
assert_eq!(s.code_distance, 3);
}
#[test]
fn test_pauli_type_equality() {
assert_eq!(PauliType::X, PauliType::X);
assert_eq!(PauliType::Z, PauliType::Z);
assert_ne!(PauliType::X, PauliType::Z);
}
#[test]
fn test_correction_no_errors() {
let c = Correction {
pauli_corrections: Vec::new(),
logical_outcome: false,
confidence: 1.0,
decode_time_ns: 100,
};
assert!(c.pauli_corrections.is_empty());
assert!(!c.logical_outcome);
assert_eq!(c.confidence, 1.0);
}
#[test]
fn test_union_find_basic() {
let mut uf = UnionFind::new(5);
assert_ne!(uf.find(0), uf.find(1));
uf.union(0, 1);
assert_eq!(uf.find(0), uf.find(1));
uf.union(2, 3);
assert_eq!(uf.find(2), uf.find(3));
assert_ne!(uf.find(0), uf.find(2));
uf.union(1, 3);
assert_eq!(uf.find(0), uf.find(3));
}
#[test]
fn test_union_find_parity() {
let mut uf = UnionFind::new(4);
uf.set_parity(0, true);
assert!(uf.cluster_parity(0));
uf.set_parity(1, true);
uf.union(0, 1);
assert!(!uf.cluster_parity(0));
}
#[test]
fn test_union_find_path_compression() {
let mut uf = UnionFind::new(10);
for i in 0..4 {
uf.union(i, i + 1);
}
let root = uf.find(0);
assert_eq!(uf.find(4), root);
}
#[test]
fn test_uf_decoder_no_errors() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(
correction.pauli_corrections.is_empty(),
"No defects should produce no corrections"
);
assert!(!correction.logical_outcome);
assert_eq!(correction.confidence, 1.0);
}
#[test]
fn test_uf_decoder_single_defect() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(
!correction.pauli_corrections.is_empty(),
"Single defect should produce corrections"
);
}
#[test]
fn test_uf_decoder_paired_defects() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(
!correction.pauli_corrections.is_empty(),
"Paired defects should produce corrections"
);
}
#[test]
fn test_uf_decoder_name() {
let decoder = UnionFindDecoder::new(5);
assert_eq!(decoder.name(), "UnionFindDecoder");
}
#[test]
fn test_uf_decoder_extract_defects_empty_syndrome() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: Vec::new(),
code_distance: 3,
num_rounds: 1,
};
let defects = decoder.extract_defects(&syndrome);
assert!(defects.is_empty());
}
#[test]
fn test_uf_decoder_extract_defects_all_false() {
let decoder = UnionFindDecoder::new(0);
let mut stabs = Vec::new();
for y in 0..2 {
for x in 0..2 {
stabs.push(StabilizerMeasurement {
x,
y,
round: 0,
value: false,
});
}
}
let syndrome = SyndromeData {
stabilizers: stabs,
code_distance: 3,
num_rounds: 1,
};
let defects = decoder.extract_defects(&syndrome);
assert!(defects.is_empty(), "All-false syndrome should have no defects");
}
#[test]
fn test_uf_decoder_extract_defects_with_flip() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: true },
],
code_distance: 3,
num_rounds: 1,
};
let defects = decoder.extract_defects(&syndrome);
assert_eq!(defects.len(), 1);
assert_eq!(defects[0].x, 1);
assert_eq!(defects[0].y, 0);
}
#[test]
fn test_uf_decoder_manhattan_distance() {
let a = Defect { x: 0, y: 0, round: 0, node_index: 0 };
let b = Defect { x: 3, y: 4, round: 1, node_index: 1 };
assert_eq!(UnionFindDecoder::manhattan_distance(&a, &b), 8);
}
#[test]
fn test_uf_decoder_boundary_distance() {
let d = Defect { x: 0, y: 0, round: 0, node_index: 0 };
assert_eq!(UnionFindDecoder::boundary_distance(&d, 5), 0);
let d2 = Defect { x: 2, y: 2, round: 0, node_index: 0 };
assert_eq!(UnionFindDecoder::boundary_distance(&d2, 5), 1);
}
#[test]
fn test_uf_decoder_multi_round() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 0, y: 0, round: 1, value: false },
],
code_distance: 3,
num_rounds: 2,
};
let defects = decoder.extract_defects(&syndrome);
assert_eq!(defects.len(), 2);
}
#[test]
fn test_uf_decoder_confidence_decreases_with_errors() {
let decoder = UnionFindDecoder::new(0);
let syndrome_low = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let corr_low = decoder.decode(&syndrome_low);
let syndrome_high = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: true },
],
code_distance: 3,
num_rounds: 1,
};
let corr_high = decoder.decode(&syndrome_high);
assert!(
corr_low.confidence >= corr_high.confidence,
"More defects should reduce confidence: {} >= {}",
corr_low.confidence,
corr_high.confidence
);
}
#[test]
fn test_uf_decoder_decode_time_recorded() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
],
code_distance: 3,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
let _ = correction.decode_time_ns;
}
#[test]
fn test_partitioned_decoder_no_errors() {
let inner = Box::new(UnionFindDecoder::new(0));
let decoder = PartitionedDecoder::new(4, inner);
let mut stabs = Vec::new();
for y in 0..4 {
for x in 0..4 {
stabs.push(StabilizerMeasurement {
x,
y,
round: 0,
value: false,
});
}
}
let syndrome = SyndromeData {
stabilizers: stabs,
code_distance: 5,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(correction.pauli_corrections.is_empty());
}
#[test]
fn test_partitioned_decoder_name() {
let inner = Box::new(UnionFindDecoder::new(0));
let decoder = PartitionedDecoder::new(4, inner);
assert_eq!(decoder.name(), "PartitionedDecoder");
}
#[test]
fn test_partitioned_decoder_single_tile() {
let inner = Box::new(UnionFindDecoder::new(0));
let decoder = PartitionedDecoder::new(100, inner);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(!correction.pauli_corrections.is_empty());
}
#[test]
fn test_partitioned_decoder_multi_tile() {
let inner = Box::new(UnionFindDecoder::new(0));
let decoder = PartitionedDecoder::new(2, inner);
let mut stabs = Vec::new();
for y in 0..6 {
for x in 0..6 {
stabs.push(StabilizerMeasurement {
x,
y,
round: 0,
value: false,
});
}
}
stabs[0].value = true;
let syndrome = SyndromeData {
stabilizers: stabs,
code_distance: 7,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(!correction.pauli_corrections.is_empty());
}
#[test]
fn test_partitioned_decoder_partition_count() {
let inner = Box::new(UnionFindDecoder::new(0));
let decoder = PartitionedDecoder::new(2, inner);
let syndrome = SyndromeData {
stabilizers: Vec::new(),
code_distance: 5,
num_rounds: 1,
};
let tiles = decoder.partition_syndrome(&syndrome);
assert_eq!(tiles.len(), 4);
}
#[test]
#[should_panic(expected = "tile_size must be positive")]
fn test_partitioned_decoder_zero_tile_size() {
let inner = Box::new(UnionFindDecoder::new(0));
let _decoder = PartitionedDecoder::new(0, inner);
}
#[test]
fn test_adaptive_code_distance_creation() {
let acd = AdaptiveCodeDistance::new(5, 3, 15);
assert_eq!(acd.current_distance, 5);
assert_eq!(acd.min_distance, 3);
assert_eq!(acd.max_distance, 15);
}
#[test]
fn test_adaptive_code_distance_even_initial() {
let acd = AdaptiveCodeDistance::new(4, 3, 15);
assert_eq!(acd.current_distance, 5);
}
#[test]
fn test_adaptive_code_distance_no_data() {
let acd = AdaptiveCodeDistance::new(5, 3, 15);
assert_eq!(acd.recommended_distance(), 5);
assert!(!acd.should_increase());
assert!(!acd.should_decrease());
}
#[test]
fn test_adaptive_code_distance_increase() {
let mut acd = AdaptiveCodeDistance::new(3, 3, 15);
for _ in 0..200 {
acd.record_error_rate(0.5);
}
assert!(acd.should_increase());
assert_eq!(acd.recommended_distance(), 5);
}
#[test]
fn test_adaptive_code_distance_decrease() {
let mut acd = AdaptiveCodeDistance::new(9, 3, 15);
for _ in 0..200 {
acd.record_error_rate(1e-10);
}
assert!(acd.should_decrease());
assert_eq!(acd.recommended_distance(), 7);
}
#[test]
fn test_adaptive_code_distance_stable() {
let mut acd = AdaptiveCodeDistance::new(5, 3, 15);
for _ in 0..200 {
acd.record_error_rate(0.001);
}
assert!(!acd.should_increase());
}
#[test]
fn test_adaptive_code_distance_at_max() {
let mut acd = AdaptiveCodeDistance::new(15, 3, 15);
for _ in 0..200 {
acd.record_error_rate(0.9);
}
assert!(!acd.should_increase(), "Cannot increase past max");
assert_eq!(acd.recommended_distance(), 15);
}
#[test]
fn test_adaptive_code_distance_at_min() {
let mut acd = AdaptiveCodeDistance::new(3, 3, 15);
for _ in 0..200 {
acd.record_error_rate(1e-15);
}
assert!(!acd.should_decrease(), "Cannot decrease past min");
}
#[test]
fn test_adaptive_code_distance_record_clamps() {
let mut acd = AdaptiveCodeDistance::new(5, 3, 15);
acd.record_error_rate(2.0);
acd.record_error_rate(-1.0);
assert_eq!(acd.error_history.len(), 2);
assert_eq!(acd.error_history[0], 1.0);
assert_eq!(acd.error_history[1], 0.0);
}
#[test]
fn test_adaptive_code_distance_window_trimming() {
let mut acd = AdaptiveCodeDistance::new(5, 3, 15);
for i in 0..500 {
acd.record_error_rate(i as f64 * 0.001);
}
assert!(acd.error_history.len() <= acd.window_size * 2);
}
#[test]
#[should_panic(expected = "min_distance must be <= max_distance")]
fn test_adaptive_code_distance_invalid_range() {
let _acd = AdaptiveCodeDistance::new(5, 10, 3);
}
#[test]
fn test_surface_code_patch_creation() {
let patch = SurfaceCodePatch {
logical_id: 0,
physical_qubits: vec![0, 1, 2, 3, 4],
code_distance: 3,
x_origin: 0,
y_origin: 0,
};
assert_eq!(patch.logical_id, 0);
assert_eq!(patch.physical_qubits.len(), 5);
}
#[test]
fn test_allocator_creation() {
let alloc = LogicalQubitAllocator::new(1000, 3);
assert_eq!(alloc.total_physical, 1000);
assert_eq!(alloc.code_distance, 3);
assert!(alloc.patches().is_empty());
}
#[test]
fn test_allocator_max_logical_qubits() {
let alloc = LogicalQubitAllocator::new(100, 3);
assert_eq!(alloc.max_logical_qubits(), 7); }
#[test]
fn test_allocator_max_logical_qubits_d5() {
let alloc = LogicalQubitAllocator::new(1000, 5);
assert_eq!(alloc.max_logical_qubits(), 24); }
#[test]
fn test_allocator_allocate_and_deallocate() {
let mut alloc = LogicalQubitAllocator::new(100, 3);
let patch = alloc.allocate().unwrap();
assert_eq!(patch.logical_id, 0);
assert_eq!(patch.code_distance, 3);
assert_eq!(patch.physical_qubits.len(), 13);
assert_eq!(alloc.patches().len(), 1);
alloc.deallocate(0);
assert!(alloc.patches().is_empty());
}
#[test]
fn test_allocator_multiple_allocations() {
let mut alloc = LogicalQubitAllocator::new(100, 3);
let max = alloc.max_logical_qubits();
for i in 0..max {
let patch = alloc.allocate();
assert!(patch.is_some(), "Should allocate patch {}", i);
}
assert!(alloc.allocate().is_none(), "Should be out of space");
}
#[test]
fn test_allocator_utilization() {
let mut alloc = LogicalQubitAllocator::new(100, 3);
assert_eq!(alloc.utilization(), 0.0);
alloc.allocate();
let expected = 13.0 / 100.0;
assert!((alloc.utilization() - expected).abs() < 1e-10);
}
#[test]
fn test_allocator_deallocate_nonexistent() {
let mut alloc = LogicalQubitAllocator::new(100, 3);
alloc.allocate();
alloc.deallocate(999); assert_eq!(alloc.patches().len(), 1);
}
#[test]
fn test_allocator_utilization_zero_physical() {
let alloc = LogicalQubitAllocator::new(0, 3);
assert_eq!(alloc.utilization(), 0.0);
assert_eq!(alloc.max_logical_qubits(), 0);
}
#[test]
fn test_allocator_reallocate_after_dealloc() {
let mut alloc = LogicalQubitAllocator::new(26, 3);
let p0 = alloc.allocate().unwrap();
let _p1 = alloc.allocate().unwrap();
assert!(alloc.allocate().is_none());
alloc.deallocate(p0.logical_id);
let p2 = alloc.allocate();
assert!(p2.is_some());
}
#[test]
fn test_decoder_benchmark_empty() {
let b = DecoderBenchmark {
total_syndromes: 0,
total_decode_time_ns: 0,
correct_corrections: 0,
logical_error_rate: 0.0,
};
assert_eq!(b.avg_decode_time_ns(), 0.0);
assert_eq!(b.throughput(), 0.0);
}
#[test]
fn test_decoder_benchmark_avg_time() {
let b = DecoderBenchmark {
total_syndromes: 100,
total_decode_time_ns: 1_000_000,
correct_corrections: 95,
logical_error_rate: 0.05,
};
assert!((b.avg_decode_time_ns() - 10_000.0).abs() < 1e-6);
}
#[test]
fn test_decoder_benchmark_throughput() {
let b = DecoderBenchmark {
total_syndromes: 1000,
total_decode_time_ns: 1_000_000_000, correct_corrections: 999,
logical_error_rate: 0.001,
};
assert!((b.throughput() - 1000.0).abs() < 1e-6);
}
#[test]
fn test_benchmark_decoder_runs() {
let decoder = UnionFindDecoder::new(0);
let result = benchmark_decoder(&decoder, 3, 0.01, 10);
assert_eq!(result.total_syndromes, 10);
assert!(result.logical_error_rate >= 0.0);
assert!(result.logical_error_rate <= 1.0);
}
#[test]
fn test_benchmark_decoder_zero_error_rate() {
let decoder = UnionFindDecoder::new(0);
let result = benchmark_decoder(&decoder, 3, 0.0, 20);
assert_eq!(result.total_syndromes, 20);
assert_eq!(result.correct_corrections, 20);
assert_eq!(result.logical_error_rate, 0.0);
}
#[test]
fn test_benchmark_decoder_high_error_rate() {
let decoder = UnionFindDecoder::new(0);
let result = benchmark_decoder(&decoder, 3, 0.9, 50);
assert_eq!(result.total_syndromes, 50);
assert!(result.logical_error_rate >= 0.0);
}
#[test]
fn test_benchmark_decoder_zero_rounds() {
let decoder = UnionFindDecoder::new(0);
let result = benchmark_decoder(&decoder, 3, 0.01, 0);
assert_eq!(result.total_syndromes, 0);
assert_eq!(result.logical_error_rate, 0.0);
}
#[test]
fn test_uf_decoder_distance_5() {
let decoder = UnionFindDecoder::new(0);
let mut stabs = Vec::new();
for y in 0..4 {
for x in 0..4 {
stabs.push(StabilizerMeasurement {
x,
y,
round: 0,
value: false,
});
}
}
stabs[5].value = true;
let syndrome = SyndromeData {
stabilizers: stabs,
code_distance: 5,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(!correction.pauli_corrections.is_empty());
}
#[test]
fn test_partitioned_matches_uf_small() {
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
StabilizerMeasurement { x: 1, y: 0, round: 0, value: false },
StabilizerMeasurement { x: 0, y: 1, round: 0, value: false },
StabilizerMeasurement { x: 1, y: 1, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
let uf = UnionFindDecoder::new(0);
let corr_uf = uf.decode(&syndrome);
let partitioned = PartitionedDecoder::new(10, Box::new(UnionFindDecoder::new(0)));
let corr_part = partitioned.decode(&syndrome);
assert_eq!(
corr_uf.pauli_corrections.is_empty(),
corr_part.pauli_corrections.is_empty()
);
}
#[test]
fn test_decoder_trait_object() {
let decoders: Vec<Box<dyn SurfaceCodeDecoder>> = vec![
Box::new(UnionFindDecoder::new(0)),
Box::new(PartitionedDecoder::new(4, Box::new(UnionFindDecoder::new(0)))),
];
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: false },
],
code_distance: 3,
num_rounds: 1,
};
for decoder in &decoders {
let correction = decoder.decode(&syndrome);
assert!(!decoder.name().is_empty());
assert!(correction.confidence >= 0.0);
}
}
#[test]
fn test_logical_outcome_parity() {
assert!(!UnionFindDecoder::infer_logical_outcome(&[
(0, PauliType::X),
(1, PauliType::X),
]));
assert!(UnionFindDecoder::infer_logical_outcome(&[
(0, PauliType::X),
]));
assert!(!UnionFindDecoder::infer_logical_outcome(&[
(0, PauliType::Z),
(1, PauliType::Z),
(2, PauliType::Z),
]));
}
#[test]
fn test_distance_1_code() {
let decoder = UnionFindDecoder::new(0);
let syndrome = SyndromeData {
stabilizers: vec![
StabilizerMeasurement { x: 0, y: 0, round: 0, value: true },
],
code_distance: 1,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
let _ = correction; }
#[test]
fn test_large_code_distance() {
let decoder = UnionFindDecoder::new(0);
let d = 11u32;
let grid = d - 1;
let mut stabs = Vec::new();
for y in 0..grid {
for x in 0..grid {
stabs.push(StabilizerMeasurement {
x,
y,
round: 0,
value: false,
});
}
}
stabs[0].value = true;
stabs[(grid * grid - 1) as usize].value = true;
let syndrome = SyndromeData {
stabilizers: stabs,
code_distance: d,
num_rounds: 1,
};
let correction = decoder.decode(&syndrome);
assert!(!correction.pauli_corrections.is_empty());
}
}