1use crate::Pauli;
2use crate::binary::try_binary_rank;
3use crate::error::{QecError, Result};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct StabilizerCode {
7 n: usize,
8 stabilizers: Vec<Pauli>,
9 stabilizer_rank: usize,
10}
11
12impl StabilizerCode {
13 pub fn from_stabilizers(n: usize, stabilizers: Vec<Pauli>) -> Result<Self> {
14 for stabilizer in &stabilizers {
15 if stabilizer.n() != n {
16 return Err(QecError::InvalidPauliWidth {
17 x_width: stabilizer.n(),
18 z_width: n,
19 });
20 }
21 }
22
23 for i in 0..stabilizers.len() {
24 for j in (i + 1)..stabilizers.len() {
25 if !stabilizers[i].try_commutes_with(&stabilizers[j])? {
26 return Err(QecError::NonCommutingStabilizers);
27 }
28 }
29 }
30
31 let symplectic_rows: Vec<Vec<u8>> =
32 stabilizers.iter().map(Pauli::to_symplectic_row).collect();
33 let stabilizer_rank = try_binary_rank(&symplectic_rows)?;
34
35 if stabilizer_rank != stabilizers.len() {
36 return Err(QecError::DependentStabilizers);
37 }
38
39 Ok(Self {
40 n,
41 stabilizers,
42 stabilizer_rank,
43 })
44 }
45
46 pub fn n(&self) -> usize {
47 self.n
48 }
49
50 pub fn stabilizers(&self) -> &[Pauli] {
51 &self.stabilizers
52 }
53
54 pub fn stabilizer_rows(&self) -> Vec<Vec<u8>> {
55 self.stabilizers
56 .iter()
57 .map(Pauli::to_symplectic_row)
58 .collect()
59 }
60
61 pub fn stabilizer_rank(&self) -> usize {
62 self.stabilizer_rank
63 }
64
65 pub fn num_logical_qubits(&self) -> usize {
66 self.n - self.stabilizer_rank
67 }
68
69 pub fn normalizer_basis(&self) -> Result<Vec<Pauli>> {
71 crate::logical::compute_normalizer_basis(self)
72 }
73
74 pub fn logical_basis(&self) -> Result<crate::logical::LogicalBasis> {
75 crate::logical::compute_logical_basis(self)
76 }
77
78 pub fn canonical_logical_basis(&self) -> Result<crate::logical::LogicalBasis> {
79 crate::logical::compute_canonical_logical_basis(self)
80 }
81}