Skip to main content

qec_code/
logical.rs

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}