1use crate::Pauli;
2use crate::code::StabilizerCode;
3use crate::error::{QecError, Result};
4use crate::gf2::BinaryRow;
5use crate::{gf2, symplectic};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct LogicalBasis {
9 pub k: usize,
10 pub logical_x: Vec<Pauli>,
11 pub logical_z: Vec<Pauli>,
12}
13
14pub fn extract_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
15 code.logical_basis()
16}
17
18pub fn compute_normalizer_basis(code: &StabilizerCode) -> Result<Vec<Pauli>> {
19 normalizer_basis_rows(code)?
20 .into_iter()
21 .map(Pauli::from_symplectic_row)
22 .collect()
23}
24
25pub fn compute_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
26 compute_canonical_logical_basis(code)
27}
28
29pub fn compute_canonical_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
30 let k = code.num_logical_qubits();
31 let logical_rows = logical_quotient_rows(code)?;
32 let pairs = symplectic::symplectic_gram_schmidt(&logical_rows)?;
33
34 if pairs.len() != k {
35 return Err(QecError::LogicalBasisNotFound);
36 }
37
38 let mut logical_x = Vec::with_capacity(k);
39 let mut logical_z = Vec::with_capacity(k);
40 for (x_like, z_like) in pairs {
41 logical_x.push(Pauli::from_symplectic_row(x_like)?);
42 logical_z.push(Pauli::from_symplectic_row(z_like)?);
43 }
44
45 Ok(LogicalBasis {
46 k,
47 logical_x,
48 logical_z,
49 })
50}
51
52fn logical_quotient_rows(code: &StabilizerCode) -> Result<Vec<BinaryRow>> {
53 let width = symplectic_width(code)?;
54 let target_count = code
55 .num_logical_qubits()
56 .checked_mul(2)
57 .ok_or(QecError::UnsupportedExhaustiveEnumeration { n: code.n() })?;
58 let mut span_rows = code.stabilizer_rows();
59 gf2::validate_rows_with_width(&span_rows, width)?;
60
61 let mut logical_rows = Vec::with_capacity(target_count);
62 for row in normalizer_basis_rows(code)? {
63 if gf2::try_in_row_span_with_width(&span_rows, width, &row)? {
64 continue;
65 }
66
67 span_rows.push(row.clone());
68 logical_rows.push(row);
69 if logical_rows.len() == target_count {
70 return Ok(logical_rows);
71 }
72 }
73
74 if logical_rows.len() == target_count {
75 Ok(logical_rows)
76 } else {
77 Err(QecError::LogicalBasisNotFound)
78 }
79}
80
81fn normalizer_basis_rows(code: &StabilizerCode) -> Result<Vec<BinaryRow>> {
82 let width = symplectic_width(code)?;
83 let stabilizer_rows = code.stabilizer_rows();
84 let constraints = symplectic::commutation_constraints_with_width(&stabilizer_rows, width)?;
85 gf2::try_nullspace_basis_with_width(&constraints, width)
86}
87
88fn symplectic_width(code: &StabilizerCode) -> Result<usize> {
89 let n = code.n();
90 n.checked_mul(2)
91 .ok_or(QecError::UnsupportedExhaustiveEnumeration { n })
92}