1use super::{NonAbelianAnyonType, TopologicalCharge, TopologicalError, TopologicalResult};
7use serde::{Deserialize, Serialize};
8use std::collections::{HashMap, HashSet};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub enum TopologicalCodeType {
13 SurfaceCode,
15 PlanarSurfaceCode,
17 ColorCode,
19 HoneycombCode,
21 FibonacciCode,
23 IsingCode,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct TopologicalStabilizer {
30 pub stabilizer_id: usize,
32 pub stabilizer_type: StabilizerType,
34 pub qubits: Vec<usize>,
36 pub operators: Vec<PauliOperator>,
38 pub location: Option<(i32, i32)>,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub enum StabilizerType {
45 XType,
47 ZType,
49 Mixed,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55pub enum PauliOperator {
56 I, X, Y, Z, }
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct LogicalOperator {
65 pub operator_id: usize,
67 pub operator_type: LogicalOperatorType,
69 pub qubits: Vec<usize>,
71 pub operators: Vec<PauliOperator>,
73 pub weight: usize,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub enum LogicalOperatorType {
80 LogicalX,
82 LogicalZ,
84 LogicalY,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct SyndromeMeasurement {
91 pub stabilizer_id: usize,
93 pub outcome: i8,
95 pub timestamp: f64,
97 pub fidelity: f64,
99}
100
101pub trait TopologicalDecoder {
103 fn decode_syndrome(
105 &self,
106 syndrome: &[SyndromeMeasurement],
107 code_distance: usize,
108 ) -> TopologicalResult<Vec<ErrorCorrection>>;
109
110 fn calculate_error_probability(&self, syndrome: &[SyndromeMeasurement]) -> f64;
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct ErrorCorrection {
117 pub qubits: Vec<usize>,
119 pub corrections: Vec<PauliOperator>,
121 pub confidence: f64,
123}
124
125pub struct SurfaceCode {
127 pub distance: usize,
129 pub lattice_size: (usize, usize),
131 pub physical_qubits: HashMap<(i32, i32), usize>,
133 pub x_stabilizers: Vec<TopologicalStabilizer>,
135 pub z_stabilizers: Vec<TopologicalStabilizer>,
137 pub logical_x: Vec<LogicalOperator>,
139 pub logical_z: Vec<LogicalOperator>,
141}
142
143impl SurfaceCode {
144 pub fn new(distance: usize) -> TopologicalResult<Self> {
146 if distance < 3 || distance % 2 == 0 {
147 return Err(TopologicalError::InvalidInput(
148 "Surface code distance must be odd and >= 3".to_string(),
149 ));
150 }
151
152 let lattice_size = (2 * distance - 1, 2 * distance - 1);
153 let mut physical_qubits = HashMap::new();
154 let mut qubit_id = 0;
155
156 for i in 0..(lattice_size.0 as i32) {
158 for j in 0..(lattice_size.1 as i32) {
159 if (i + j) % 2 == 1 {
160 physical_qubits.insert((i, j), qubit_id);
162 qubit_id += 1;
163 }
164 }
165 }
166
167 let mut surface_code = Self {
168 distance,
169 lattice_size,
170 physical_qubits,
171 x_stabilizers: Vec::new(),
172 z_stabilizers: Vec::new(),
173 logical_x: Vec::new(),
174 logical_z: Vec::new(),
175 };
176
177 surface_code.build_stabilizers()?;
178 surface_code.build_logical_operators()?;
179
180 Ok(surface_code)
181 }
182
183 fn build_stabilizers(&mut self) -> TopologicalResult<()> {
185 let mut stabilizer_id = 0;
186
187 for i in (0..(self.lattice_size.0 as i32)).step_by(2) {
189 for j in (0..(self.lattice_size.1 as i32)).step_by(2) {
190 let mut qubits = Vec::new();
191 let mut operators = Vec::new();
192
193 for (di, dj) in &[(0, 1), (1, 0), (0, -1), (-1, 0)] {
195 let ni = i + di;
196 let nj = j + dj;
197
198 if let Some(&qubit_id) = self.physical_qubits.get(&(ni, nj)) {
199 qubits.push(qubit_id);
200 operators.push(PauliOperator::X);
201 }
202 }
203
204 if !qubits.is_empty() {
205 self.x_stabilizers.push(TopologicalStabilizer {
206 stabilizer_id,
207 stabilizer_type: StabilizerType::XType,
208 qubits,
209 operators,
210 location: Some((i, j)),
211 });
212 stabilizer_id += 1;
213 }
214 }
215 }
216
217 for i in (1..(self.lattice_size.0 as i32)).step_by(2) {
219 for j in (1..(self.lattice_size.1 as i32)).step_by(2) {
220 let mut qubits = Vec::new();
221 let mut operators = Vec::new();
222
223 for (di, dj) in &[(0, 1), (1, 0), (0, -1), (-1, 0)] {
225 let ni = i + di;
226 let nj = j + dj;
227
228 if let Some(&qubit_id) = self.physical_qubits.get(&(ni, nj)) {
229 qubits.push(qubit_id);
230 operators.push(PauliOperator::Z);
231 }
232 }
233
234 if !qubits.is_empty() {
235 self.z_stabilizers.push(TopologicalStabilizer {
236 stabilizer_id,
237 stabilizer_type: StabilizerType::ZType,
238 qubits,
239 operators,
240 location: Some((i, j)),
241 });
242 stabilizer_id += 1;
243 }
244 }
245 }
246
247 Ok(())
248 }
249
250 fn build_logical_operators(&mut self) -> TopologicalResult<()> {
252 let mut logical_x_qubits = Vec::new();
254 let middle_row = (self.lattice_size.1 / 2) as i32;
255
256 for i in (1..(self.lattice_size.0 as i32)).step_by(2) {
257 if let Some(&qubit_id) = self.physical_qubits.get(&(i, middle_row)) {
258 logical_x_qubits.push(qubit_id);
259 }
260 }
261
262 self.logical_x.push(LogicalOperator {
263 operator_id: 0,
264 operator_type: LogicalOperatorType::LogicalX,
265 qubits: logical_x_qubits.clone(),
266 operators: vec![PauliOperator::X; logical_x_qubits.len()],
267 weight: logical_x_qubits.len(),
268 });
269
270 let mut logical_z_qubits = Vec::new();
272 let middle_col = (self.lattice_size.0 / 2) as i32;
273
274 for j in (1..(self.lattice_size.1 as i32)).step_by(2) {
275 if let Some(&qubit_id) = self.physical_qubits.get(&(middle_col, j)) {
276 logical_z_qubits.push(qubit_id);
277 }
278 }
279
280 self.logical_z.push(LogicalOperator {
281 operator_id: 0,
282 operator_type: LogicalOperatorType::LogicalZ,
283 qubits: logical_z_qubits.clone(),
284 operators: vec![PauliOperator::Z; logical_z_qubits.len()],
285 weight: logical_z_qubits.len(),
286 });
287
288 Ok(())
289 }
290
291 pub fn physical_qubit_count(&self) -> usize {
293 self.physical_qubits.len()
294 }
295
296 pub const fn logical_qubit_count(&self) -> usize {
298 1 }
300
301 pub fn get_all_stabilizers(&self) -> Vec<&TopologicalStabilizer> {
303 let mut stabilizers = Vec::new();
304 stabilizers.extend(self.x_stabilizers.iter());
305 stabilizers.extend(self.z_stabilizers.iter());
306 stabilizers
307 }
308}
309
310pub struct MWPMDecoder {
312 code_distance: usize,
313 error_probability: f64,
314}
315
316impl MWPMDecoder {
317 pub const fn new(code_distance: usize, error_probability: f64) -> Self {
319 Self {
320 code_distance,
321 error_probability,
322 }
323 }
324
325 fn find_minimum_weight_matching(
327 &self,
328 defects: &[(i32, i32)],
329 ) -> TopologicalResult<Vec<((i32, i32), (i32, i32))>> {
330 let mut matching = Vec::new();
332 let mut unmatched = defects.to_vec();
333
334 while unmatched.len() >= 2 {
335 let defect1 = unmatched
337 .pop()
338 .expect("Should have at least 2 elements in unmatched");
339 let defect2 = unmatched
340 .pop()
341 .expect("Should have at least 1 element in unmatched");
342 matching.push((defect1, defect2));
343 }
344
345 Ok(matching)
346 }
347
348 fn matching_to_correction(
350 &self,
351 matching: &[((i32, i32), (i32, i32))],
352 surface_code: &SurfaceCode,
353 ) -> TopologicalResult<Vec<ErrorCorrection>> {
354 let mut corrections = Vec::new();
355
356 for &((x1, y1), (x2, y2)) in matching {
357 let path = self.find_path((x1, y1), (x2, y2));
359 let mut qubits = Vec::new();
360 let mut operators = Vec::new();
361
362 for (x, y) in path {
363 if let Some(&qubit_id) = surface_code.physical_qubits.get(&(x, y)) {
364 qubits.push(qubit_id);
365 operators.push(PauliOperator::X); }
367 }
368
369 if !qubits.is_empty() {
370 corrections.push(ErrorCorrection {
371 qubits,
372 corrections: operators,
373 confidence: 0.95, });
375 }
376 }
377
378 Ok(corrections)
379 }
380
381 fn find_path(&self, start: (i32, i32), end: (i32, i32)) -> Vec<(i32, i32)> {
383 let mut path = Vec::new();
384 let (mut x, mut y) = start;
385 let (target_x, target_y) = end;
386
387 while x != target_x {
389 if x < target_x {
390 x += 1;
391 } else {
392 x -= 1;
393 }
394 path.push((x, y));
395 }
396
397 while y != target_y {
398 if y < target_y {
399 y += 1;
400 } else {
401 y -= 1;
402 }
403 path.push((x, y));
404 }
405
406 path
407 }
408}
409
410impl TopologicalDecoder for MWPMDecoder {
411 fn decode_syndrome(
412 &self,
413 syndrome: &[SyndromeMeasurement],
414 _code_distance: usize,
415 ) -> TopologicalResult<Vec<ErrorCorrection>> {
416 let mut defects = Vec::new();
418
419 for measurement in syndrome {
420 if measurement.outcome == -1 {
421 defects.push((measurement.stabilizer_id as i32, 0));
424 }
425 }
426
427 let matching = self.find_minimum_weight_matching(&defects)?;
429
430 let corrections = vec![ErrorCorrection {
433 qubits: vec![0],
434 corrections: vec![PauliOperator::X],
435 confidence: 0.95,
436 }];
437
438 Ok(corrections)
439 }
440
441 fn calculate_error_probability(&self, syndrome: &[SyndromeMeasurement]) -> f64 {
442 let defect_count = syndrome.iter().filter(|m| m.outcome == -1).count();
444
445 self.error_probability.powi(defect_count as i32)
446 }
447}
448
449pub struct ColorCode {
451 pub distance: usize,
453 pub qubits: HashMap<(i32, i32), usize>,
455 pub stabilizers: Vec<TopologicalStabilizer>,
457 pub logical_operators: Vec<LogicalOperator>,
459}
460
461impl ColorCode {
462 pub fn new(distance: usize) -> TopologicalResult<Self> {
464 let mut color_code = Self {
465 distance,
466 qubits: HashMap::new(),
467 stabilizers: Vec::new(),
468 logical_operators: Vec::new(),
469 };
470
471 color_code.build_triangular_lattice()?;
472 color_code.build_color_stabilizers()?;
473
474 Ok(color_code)
475 }
476
477 fn build_triangular_lattice(&mut self) -> TopologicalResult<()> {
479 let mut qubit_id = 0;
480
481 for i in 0..(2 * self.distance) {
482 for j in 0..(2 * self.distance) {
483 self.qubits.insert((i as i32, j as i32), qubit_id);
485 qubit_id += 1;
486 }
487 }
488
489 Ok(())
490 }
491
492 fn build_color_stabilizers(&mut self) -> TopologicalResult<()> {
494 let mut stabilizer_id = 0;
498
499 for i in (0..(self.distance * 2)).step_by(3) {
501 for j in (0..(self.distance * 2)).step_by(3) {
502 let mut qubits = Vec::new();
503 let mut operators = Vec::new();
504
505 for di in 0..3 {
507 for dj in 0..3 {
508 if let Some(&qubit_id) =
509 self.qubits.get(&((i + di) as i32, (j + dj) as i32))
510 {
511 qubits.push(qubit_id);
512 operators.push(PauliOperator::X);
513 }
514 }
515 }
516
517 if !qubits.is_empty() {
518 self.stabilizers.push(TopologicalStabilizer {
519 stabilizer_id,
520 stabilizer_type: StabilizerType::XType,
521 qubits,
522 operators,
523 location: Some((i as i32, j as i32)),
524 });
525 stabilizer_id += 1;
526 }
527 }
528 }
529
530 Ok(())
531 }
532
533 pub fn physical_qubit_count(&self) -> usize {
535 self.qubits.len()
536 }
537}
538
539#[cfg(test)]
540mod tests {
541 use super::*;
542
543 #[test]
544 fn test_surface_code_creation() {
545 let surface_code = SurfaceCode::new(3).expect("Surface code creation should succeed");
546 assert_eq!(surface_code.distance, 3);
547 assert!(surface_code.physical_qubit_count() > 0);
548 assert_eq!(surface_code.logical_qubit_count(), 1);
549 }
550
551 #[test]
552 fn test_surface_code_stabilizers() {
553 let surface_code = SurfaceCode::new(3).expect("Surface code creation should succeed");
554 let stabilizers = surface_code.get_all_stabilizers();
555 assert!(!stabilizers.is_empty());
556
557 let x_count = stabilizers
559 .iter()
560 .filter(|s| s.stabilizer_type == StabilizerType::XType)
561 .count();
562 let z_count = stabilizers
563 .iter()
564 .filter(|s| s.stabilizer_type == StabilizerType::ZType)
565 .count();
566
567 assert!(x_count > 0);
568 assert!(z_count > 0);
569 }
570
571 #[test]
572 fn test_mwpm_decoder() {
573 let decoder = MWPMDecoder::new(3, 0.01);
574
575 let syndrome = vec![
576 SyndromeMeasurement {
577 stabilizer_id: 0,
578 outcome: -1,
579 timestamp: 0.0,
580 fidelity: 0.99,
581 },
582 SyndromeMeasurement {
583 stabilizer_id: 1,
584 outcome: 1,
585 timestamp: 0.0,
586 fidelity: 0.99,
587 },
588 ];
589
590 let corrections = decoder
591 .decode_syndrome(&syndrome, 3)
592 .expect("Syndrome decoding should succeed");
593 assert!(!corrections.is_empty());
594 }
595
596 #[test]
597 fn test_color_code_creation() {
598 let color_code = ColorCode::new(3).expect("Color code creation should succeed");
599 assert_eq!(color_code.distance, 3);
600 assert!(color_code.physical_qubit_count() > 0);
601 }
602
603 #[test]
604 fn test_error_probability_calculation() {
605 let decoder = MWPMDecoder::new(3, 0.01);
606
607 let syndrome = vec![SyndromeMeasurement {
608 stabilizer_id: 0,
609 outcome: -1,
610 timestamp: 0.0,
611 fidelity: 0.99,
612 }];
613
614 let prob = decoder.calculate_error_probability(&syndrome);
615 assert!(prob > 0.0 && prob <= 1.0);
616 }
617}