1use crate::error::{QuantRS2Error, QuantRS2Result};
7use ndarray::{Array1, Array2};
8use num_complex::Complex64;
9use std::collections::HashMap;
10use std::f64::consts::PI;
11use std::fmt;
12
13type FusionCoeff = Complex64;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub struct AnyonType {
19 pub id: u32,
21 pub label: &'static str,
23}
24
25impl AnyonType {
26 pub const fn new(id: u32, label: &'static str) -> Self {
28 Self { id, label }
29 }
30
31 pub const VACUUM: Self = Self::new(0, "1");
33}
34
35impl fmt::Display for AnyonType {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "{}", self.label)
38 }
39}
40
41pub trait AnyonModel: Send + Sync {
43 fn anyon_types(&self) -> &[AnyonType];
45
46 fn quantum_dimension(&self, anyon: AnyonType) -> f64;
48
49 fn topological_spin(&self, anyon: AnyonType) -> Complex64;
51
52 fn can_fuse(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> bool;
54
55 fn fusion_multiplicity(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> u32;
57
58 fn f_symbol(
60 &self,
61 a: AnyonType,
62 b: AnyonType,
63 c: AnyonType,
64 d: AnyonType,
65 e: AnyonType,
66 f: AnyonType,
67 ) -> FusionCoeff;
68
69 fn r_symbol(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> FusionCoeff;
71
72 fn name(&self) -> &str;
74
75 fn is_modular(&self) -> bool {
77 self.anyon_types()
78 .iter()
79 .all(|&a| self.quantum_dimension(a) > 0.0)
80 }
81
82 fn total_quantum_dimension(&self) -> f64 {
84 self.anyon_types()
85 .iter()
86 .map(|&a| self.quantum_dimension(a).powi(2))
87 .sum::<f64>()
88 .sqrt()
89 }
90}
91
92pub struct FibonacciModel {
94 anyons: Vec<AnyonType>,
95 phi: f64, }
97
98impl FibonacciModel {
99 pub fn new() -> Self {
101 let phi = (1.0 + 5.0_f64.sqrt()) / 2.0;
102 let anyons = vec![
103 AnyonType::new(0, "1"), AnyonType::new(1, "τ"), ];
106
107 Self { anyons, phi }
108 }
109}
110
111impl Default for FibonacciModel {
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117impl AnyonModel for FibonacciModel {
118 fn anyon_types(&self) -> &[AnyonType] {
119 &self.anyons
120 }
121
122 fn quantum_dimension(&self, anyon: AnyonType) -> f64 {
123 match anyon.id {
124 0 => 1.0, 1 => self.phi, _ => 0.0,
127 }
128 }
129
130 fn topological_spin(&self, anyon: AnyonType) -> Complex64 {
131 match anyon.id {
132 0 => Complex64::new(1.0, 0.0), 1 => Complex64::from_polar(1.0, 4.0 * PI / 5.0), _ => Complex64::new(0.0, 0.0),
135 }
136 }
137
138 fn can_fuse(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> bool {
139 self.fusion_multiplicity(a, b, c) > 0
140 }
141
142 fn fusion_multiplicity(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> u32 {
143 match (a.id, b.id, c.id) {
144 (0, x, y) | (x, 0, y) if x == y => 1, (1, 1, 0) => 1, (1, 1, 1) => 1, _ => 0,
148 }
149 }
150
151 fn f_symbol(
152 &self,
153 a: AnyonType,
154 b: AnyonType,
155 c: AnyonType,
156 d: AnyonType,
157 e: AnyonType,
158 f: AnyonType,
159 ) -> FusionCoeff {
160 if a.id == 1 && b.id == 1 && c.id == 1 && d.id == 1 {
163 if e.id == 1 && f.id == 1 {
164 Complex64::new(1.0 / self.phi, 0.0)
166 } else if e.id == 1 && f.id == 0 {
167 Complex64::new(1.0 / self.phi.sqrt(), 0.0)
169 } else if e.id == 0 && f.id == 1 {
170 Complex64::new(1.0 / self.phi.sqrt(), 0.0)
172 } else {
173 Complex64::new(0.0, 0.0)
174 }
175 } else {
176 if self.is_valid_fusion_tree(a, b, c, d, e, f) {
178 Complex64::new(1.0, 0.0)
179 } else {
180 Complex64::new(0.0, 0.0)
181 }
182 }
183 }
184
185 fn r_symbol(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> FusionCoeff {
186 if self.can_fuse(a, b, c) {
188 let theta_a = self.topological_spin(a);
189 let theta_b = self.topological_spin(b);
190 let theta_c = self.topological_spin(c);
191 let r = theta_c / (theta_a * theta_b);
192 Complex64::from_polar(1.0, r.arg())
194 } else {
195 Complex64::new(0.0, 0.0)
196 }
197 }
198
199 fn name(&self) -> &str {
200 "Fibonacci"
201 }
202}
203
204impl FibonacciModel {
205 fn is_valid_fusion_tree(
207 &self,
208 a: AnyonType,
209 b: AnyonType,
210 c: AnyonType,
211 d: AnyonType,
212 e: AnyonType,
213 f: AnyonType,
214 ) -> bool {
215 self.can_fuse(a, b, e)
216 && self.can_fuse(e, c, d)
217 && self.can_fuse(b, c, f)
218 && self.can_fuse(a, f, d)
219 }
220}
221
222pub struct IsingModel {
224 anyons: Vec<AnyonType>,
225}
226
227impl IsingModel {
228 pub fn new() -> Self {
230 let anyons = vec![
231 AnyonType::new(0, "1"), AnyonType::new(1, "σ"), AnyonType::new(2, "ψ"), ];
235
236 Self { anyons }
237 }
238}
239
240impl Default for IsingModel {
241 fn default() -> Self {
242 Self::new()
243 }
244}
245
246impl AnyonModel for IsingModel {
247 fn anyon_types(&self) -> &[AnyonType] {
248 &self.anyons
249 }
250
251 fn quantum_dimension(&self, anyon: AnyonType) -> f64 {
252 match anyon.id {
253 0 => 1.0, 1 => 2.0_f64.sqrt(), 2 => 1.0, _ => 0.0,
257 }
258 }
259
260 fn topological_spin(&self, anyon: AnyonType) -> Complex64 {
261 match anyon.id {
262 0 => Complex64::new(1.0, 0.0), 1 => Complex64::from_polar(1.0, PI / 8.0), 2 => Complex64::new(-1.0, 0.0), _ => Complex64::new(0.0, 0.0),
266 }
267 }
268
269 fn can_fuse(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> bool {
270 self.fusion_multiplicity(a, b, c) > 0
271 }
272
273 fn fusion_multiplicity(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> u32 {
274 match (a.id, b.id, c.id) {
275 (0, x, y) | (x, 0, y) if x == y => 1,
277 (1, 1, 0) | (1, 1, 2) => 1,
279 (1, 2, 1) | (2, 1, 1) => 1,
281 (2, 2, 0) => 1,
283 _ => 0,
284 }
285 }
286
287 fn f_symbol(
288 &self,
289 a: AnyonType,
290 b: AnyonType,
291 c: AnyonType,
292 d: AnyonType,
293 e: AnyonType,
294 f: AnyonType,
295 ) -> FusionCoeff {
296 if a.id == 1 && b.id == 1 && c.id == 1 && d.id == 1 {
299 match (e.id, f.id) {
300 (0, 0) | (2, 2) => Complex64::new(0.5, 0.0),
301 (0, 2) | (2, 0) => Complex64::new(0.5, 0.0),
302 _ => Complex64::new(0.0, 0.0),
303 }
304 } else if self.is_valid_fusion_tree(a, b, c, d, e, f) {
305 Complex64::new(1.0, 0.0)
306 } else {
307 Complex64::new(0.0, 0.0)
308 }
309 }
310
311 fn r_symbol(&self, a: AnyonType, b: AnyonType, c: AnyonType) -> FusionCoeff {
312 match (a.id, b.id, c.id) {
314 (1, 1, 2) => Complex64::new(-1.0, 0.0),
316 (2, 2, 0) => Complex64::new(-1.0, 0.0),
318 _ => {
320 if self.can_fuse(a, b, c) {
321 let theta_a = self.topological_spin(a);
322 let theta_b = self.topological_spin(b);
323 let theta_c = self.topological_spin(c);
324 theta_c / (theta_a * theta_b)
325 } else {
326 Complex64::new(0.0, 0.0)
327 }
328 }
329 }
330 }
331
332 fn name(&self) -> &str {
333 "Ising"
334 }
335}
336
337impl IsingModel {
338 fn is_valid_fusion_tree(
340 &self,
341 a: AnyonType,
342 b: AnyonType,
343 c: AnyonType,
344 d: AnyonType,
345 e: AnyonType,
346 f: AnyonType,
347 ) -> bool {
348 self.can_fuse(a, b, e)
349 && self.can_fuse(e, c, d)
350 && self.can_fuse(b, c, f)
351 && self.can_fuse(a, f, d)
352 }
353}
354
355#[derive(Debug, Clone)]
357pub struct AnyonWorldline {
358 pub anyon_type: AnyonType,
360 pub start: (f64, f64, f64),
362 pub end: (f64, f64, f64),
364 pub path: Vec<(f64, f64, f64)>,
366}
367
368#[derive(Debug, Clone)]
370pub struct BraidingOperation {
371 pub anyon1: usize,
373 pub anyon2: usize,
375 pub over: bool,
377}
378
379#[derive(Debug, Clone)]
381pub struct FusionTree {
382 pub external: Vec<AnyonType>,
384 pub internal: Vec<AnyonType>,
386 pub structure: Vec<(usize, usize)>,
388}
389
390impl FusionTree {
391 pub fn new(external: Vec<AnyonType>) -> Self {
393 let n = external.len();
394 let internal = if n > 2 {
395 vec![AnyonType::VACUUM; n - 2]
396 } else {
397 vec![]
398 };
399 let structure = if n > 1 {
400 (0..n - 1).map(|i| (i, i + 1)).collect()
401 } else {
402 vec![]
403 };
404
405 Self {
406 external,
407 internal,
408 structure,
409 }
410 }
411
412 pub fn total_charge(&self) -> AnyonType {
414 if self.internal.is_empty() {
415 if self.external.is_empty() {
416 AnyonType::VACUUM
417 } else if self.external.len() == 1 {
418 self.external[0]
419 } else {
420 AnyonType::VACUUM
422 }
423 } else {
424 *self.internal.last().unwrap()
425 }
426 }
427
428 pub fn set_total_charge(&mut self, charge: AnyonType) {
430 if self.external.len() == 2 && self.internal.is_empty() {
431 self.structure = vec![(charge.id as usize, charge.id as usize)];
434 }
435 }
436
437 pub fn get_fusion_outcome(&self) -> Option<AnyonType> {
439 if self.external.len() == 2 && self.internal.is_empty() && !self.structure.is_empty() {
440 let charge_id = self.structure[0].0 as u32;
441 Some(AnyonType::new(
442 charge_id,
443 match charge_id {
444 0 => "1",
445 1 => "σ",
446 2 => "ψ",
447 _ => "τ",
448 },
449 ))
450 } else {
451 None
452 }
453 }
454}
455
456pub struct TopologicalQC {
458 model: Box<dyn AnyonModel>,
460 fusion_trees: Vec<FusionTree>,
462 amplitudes: Array1<Complex64>,
464}
465
466impl TopologicalQC {
467 pub fn new(model: Box<dyn AnyonModel>, anyons: Vec<AnyonType>) -> QuantRS2Result<Self> {
469 let fusion_trees = Self::generate_fusion_trees(&*model, anyons)?;
471 let n = fusion_trees.len();
472
473 if n == 0 {
474 return Err(QuantRS2Error::InvalidInput(
475 "No valid fusion trees for given anyons".to_string(),
476 ));
477 }
478
479 let amplitudes = Array1::from_elem(n, Complex64::new(1.0 / (n as f64).sqrt(), 0.0));
481
482 Ok(Self {
483 model,
484 fusion_trees,
485 amplitudes,
486 })
487 }
488
489 fn generate_fusion_trees(
491 model: &dyn AnyonModel,
492 anyons: Vec<AnyonType>,
493 ) -> QuantRS2Result<Vec<FusionTree>> {
494 if anyons.len() < 2 {
495 return Ok(vec![FusionTree::new(anyons)]);
496 }
497
498 let mut trees = Vec::new();
499
500 if anyons.len() == 2 {
502 let a = anyons[0];
503 let b = anyons[1];
504
505 for c in model.anyon_types() {
507 if model.can_fuse(a, b, *c) {
508 let mut tree = FusionTree::new(anyons.clone());
509 tree.set_total_charge(*c);
510 trees.push(tree);
511 }
512 }
513 } else {
514 trees.push(FusionTree::new(anyons.clone()));
516 }
517
518 if trees.is_empty() {
519 trees.push(FusionTree::new(anyons));
521 }
522
523 Ok(trees)
524 }
525
526 pub fn braid(&mut self, op: &BraidingOperation) -> QuantRS2Result<()> {
528 let braid_matrix = self.compute_braiding_matrix(op)?;
530
531 self.amplitudes = braid_matrix.dot(&self.amplitudes);
533
534 Ok(())
535 }
536
537 fn compute_braiding_matrix(&self, op: &BraidingOperation) -> QuantRS2Result<Array2<Complex64>> {
539 let n = self.fusion_trees.len();
540 let mut matrix = Array2::zeros((n, n));
541
542 for (i, tree) in self.fusion_trees.iter().enumerate() {
544 if op.anyon1 < tree.external.len() && op.anyon2 < tree.external.len() {
545 let a = tree.external[op.anyon1];
546 let b = tree.external[op.anyon2];
547
548 let c = if let Some(charge) = tree.get_fusion_outcome() {
550 charge
551 } else if tree.internal.is_empty() {
552 tree.total_charge()
553 } else {
554 tree.internal[0]
555 };
556
557 let r_symbol = if op.over {
558 self.model.r_symbol(a, b, c)
559 } else {
560 self.model.r_symbol(a, b, c).conj()
561 };
562
563 matrix[(i, i)] = r_symbol;
564 } else {
565 matrix[(i, i)] = Complex64::new(1.0, 0.0);
567 }
568 }
569
570 Ok(matrix)
571 }
572
573 pub fn measure_charge(&self) -> (AnyonType, f64) {
575 let mut charge_probs: HashMap<u32, f64> = HashMap::new();
577
578 for (tree, &) in self.fusion_trees.iter().zip(&self.amplitudes) {
579 let charge = if let Some(c) = tree.get_fusion_outcome() {
580 c
581 } else {
582 tree.total_charge()
583 };
584 *charge_probs.entry(charge.id).or_insert(0.0) += amp.norm_sqr();
585 }
586
587 let (charge_id, prob) = charge_probs
588 .into_iter()
589 .max_by(|(_, p1), (_, p2)| p1.partial_cmp(p2).unwrap())
590 .unwrap_or((0, 0.0));
591
592 let charge = self
593 .model
594 .anyon_types()
595 .iter()
596 .find(|a| a.id == charge_id)
597 .copied()
598 .unwrap_or(AnyonType::VACUUM);
599
600 (charge, prob)
601 }
602}
603
604#[derive(Debug, Clone)]
606pub struct TopologicalGate {
607 pub braids: Vec<BraidingOperation>,
609 pub comp_dim: usize,
611}
612
613impl TopologicalGate {
614 pub fn new(braids: Vec<BraidingOperation>, comp_dim: usize) -> Self {
616 Self { braids, comp_dim }
617 }
618
619 pub fn cnot() -> Self {
621 let braids = vec![
623 BraidingOperation {
624 anyon1: 0,
625 anyon2: 1,
626 over: true,
627 },
628 BraidingOperation {
629 anyon1: 2,
630 anyon2: 3,
631 over: true,
632 },
633 BraidingOperation {
634 anyon1: 1,
635 anyon2: 2,
636 over: false,
637 },
638 ];
639
640 Self::new(braids, 4)
641 }
642
643 pub fn to_matrix(&self, _model: &dyn AnyonModel) -> QuantRS2Result<Array2<Complex64>> {
645 Ok(Array2::eye(self.comp_dim))
648 }
649}
650
651pub struct ToricCode {
653 pub size: usize,
655 pub vertex_ops: Vec<Vec<usize>>,
657 pub plaquette_ops: Vec<Vec<usize>>,
659}
660
661impl ToricCode {
662 pub fn new(size: usize) -> Self {
664 let mut vertex_ops = Vec::new();
665 let mut plaquette_ops = Vec::new();
666
667 for i in 0..size {
670 for j in 0..size {
671 let v_op = vec![
673 2 * (i * size + j), 2 * (i * size + j) + 1, ];
676 vertex_ops.push(v_op);
677
678 let p_op = vec![
680 2 * (i * size + j),
681 2 * (i * size + (j + 1) % size),
682 2 * (((i + 1) % size) * size + j),
683 2 * (i * size + j) + 1,
684 ];
685 plaquette_ops.push(p_op);
686 }
687 }
688
689 Self {
690 size,
691 vertex_ops,
692 plaquette_ops,
693 }
694 }
695
696 pub fn num_qubits(&self) -> usize {
698 2 * self.size * self.size
699 }
700
701 pub fn num_logical_qubits(&self) -> usize {
703 2 }
705
706 pub fn create_anyons(&self, vertices: &[usize], plaquettes: &[usize]) -> Vec<AnyonType> {
708 let mut anyons = Vec::new();
709
710 for _ in vertices {
712 anyons.push(AnyonType::new(1, "e"));
713 }
714
715 for _ in plaquettes {
717 anyons.push(AnyonType::new(2, "m"));
718 }
719
720 anyons
721 }
722}
723
724#[cfg(test)]
725mod tests {
726 use super::*;
727
728 #[test]
729 fn test_fibonacci_model() {
730 let model = FibonacciModel::new();
731
732 assert_eq!(model.quantum_dimension(AnyonType::VACUUM), 1.0);
734 assert!((model.quantum_dimension(AnyonType::new(1, "τ")) - 1.618).abs() < 0.001);
735
736 assert_eq!(
738 model.fusion_multiplicity(
739 AnyonType::VACUUM,
740 AnyonType::new(1, "τ"),
741 AnyonType::new(1, "τ")
742 ),
743 1
744 );
745
746 let expected_dim = (1.0 + model.phi.powi(2)).sqrt();
749 assert!((model.total_quantum_dimension() - expected_dim).abs() < 0.001);
750 }
751
752 #[test]
753 fn test_ising_model() {
754 let model = IsingModel::new();
755
756 assert_eq!(model.quantum_dimension(AnyonType::VACUUM), 1.0);
758 assert!((model.quantum_dimension(AnyonType::new(1, "σ")) - 1.414).abs() < 0.001);
759 assert_eq!(model.quantum_dimension(AnyonType::new(2, "ψ")), 1.0);
760
761 assert_eq!(
763 model.fusion_multiplicity(
764 AnyonType::new(1, "σ"),
765 AnyonType::new(1, "σ"),
766 AnyonType::VACUUM
767 ),
768 1
769 );
770 assert_eq!(
771 model.fusion_multiplicity(
772 AnyonType::new(1, "σ"),
773 AnyonType::new(1, "σ"),
774 AnyonType::new(2, "ψ")
775 ),
776 1
777 );
778 }
779
780 #[test]
781 fn test_fusion_tree() {
782 let anyons = vec![
783 AnyonType::new(1, "τ"),
784 AnyonType::new(1, "τ"),
785 AnyonType::new(1, "τ"),
786 ];
787
788 let tree = FusionTree::new(anyons);
789 assert_eq!(tree.external.len(), 3);
790 assert_eq!(tree.internal.len(), 1);
791 }
792
793 #[test]
794 fn test_topological_qc() {
795 let model = Box::new(FibonacciModel::new());
796 let anyons = vec![AnyonType::new(1, "τ"), AnyonType::new(1, "τ")];
797
798 let qc = TopologicalQC::new(model, anyons).unwrap();
799 assert_eq!(qc.fusion_trees.len(), 2);
801
802 let (charge, _prob) = qc.measure_charge();
804 assert!(charge.id == 0 || charge.id == 1); }
806
807 #[test]
808 fn test_toric_code() {
809 let toric = ToricCode::new(4);
810
811 assert_eq!(toric.num_qubits(), 32); assert_eq!(toric.num_logical_qubits(), 2);
813
814 let anyons = toric.create_anyons(&[0, 1], &[2]);
816 assert_eq!(anyons.len(), 3);
817 }
818
819 #[test]
820 fn test_braiding_operation() {
821 let model = Box::new(IsingModel::new());
822 let anyons = vec![AnyonType::new(1, "σ"), AnyonType::new(1, "σ")];
823
824 let mut qc = TopologicalQC::new(model, anyons).unwrap();
825
826 let initial_norm: f64 = qc.amplitudes.iter().map(|a| a.norm_sqr()).sum();
828 assert!(
829 (initial_norm - 1.0).abs() < 1e-10,
830 "Initial state not normalized: {}",
831 initial_norm
832 );
833
834 let braid = BraidingOperation {
836 anyon1: 0,
837 anyon2: 1,
838 over: true,
839 };
840
841 qc.braid(&braid).unwrap();
842
843 let norm: f64 = qc.amplitudes.iter().map(|a| a.norm_sqr()).sum();
845 assert!(
846 (norm - 1.0).abs() < 1e-10,
847 "Final state not normalized: {}",
848 norm
849 );
850 }
851}