qec-code 0.3.0

Rust primitives for constructing and analyzing quantum error-correcting codes
Documentation
use crate::Pauli;
use crate::code::StabilizerCode;
use crate::error::{QecError, Result};
use crate::gf2::BinaryRow;
use crate::{gf2, symplectic};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogicalBasis {
    pub k: usize,
    pub logical_x: Vec<Pauli>,
    pub logical_z: Vec<Pauli>,
}

pub fn extract_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
    code.logical_basis()
}

pub fn compute_normalizer_basis(code: &StabilizerCode) -> Result<Vec<Pauli>> {
    normalizer_basis_rows(code)?
        .into_iter()
        .map(Pauli::from_symplectic_row)
        .collect()
}

pub fn compute_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
    compute_canonical_logical_basis(code)
}

pub fn compute_canonical_logical_basis(code: &StabilizerCode) -> Result<LogicalBasis> {
    let k = code.num_logical_qubits();
    let logical_rows = logical_quotient_rows(code)?;
    let pairs = symplectic::symplectic_gram_schmidt(&logical_rows)?;

    if pairs.len() != k {
        return Err(QecError::LogicalBasisNotFound);
    }

    let mut logical_x = Vec::with_capacity(k);
    let mut logical_z = Vec::with_capacity(k);
    for (x_like, z_like) in pairs {
        logical_x.push(Pauli::from_symplectic_row(x_like)?);
        logical_z.push(Pauli::from_symplectic_row(z_like)?);
    }

    Ok(LogicalBasis {
        k,
        logical_x,
        logical_z,
    })
}

fn logical_quotient_rows(code: &StabilizerCode) -> Result<Vec<BinaryRow>> {
    let width = symplectic_width(code)?;
    let target_count = code
        .num_logical_qubits()
        .checked_mul(2)
        .ok_or(QecError::UnsupportedExhaustiveEnumeration { n: code.n() })?;
    let mut span_rows = code.stabilizer_rows();
    gf2::validate_rows_with_width(&span_rows, width)?;

    let mut logical_rows = Vec::with_capacity(target_count);
    for row in normalizer_basis_rows(code)? {
        if gf2::try_in_row_span_with_width(&span_rows, width, &row)? {
            continue;
        }

        span_rows.push(row.clone());
        logical_rows.push(row);
        if logical_rows.len() == target_count {
            return Ok(logical_rows);
        }
    }

    if logical_rows.len() == target_count {
        Ok(logical_rows)
    } else {
        Err(QecError::LogicalBasisNotFound)
    }
}

fn normalizer_basis_rows(code: &StabilizerCode) -> Result<Vec<BinaryRow>> {
    let width = symplectic_width(code)?;
    let stabilizer_rows = code.stabilizer_rows();
    let constraints = symplectic::commutation_constraints_with_width(&stabilizer_rows, width)?;
    gf2::try_nullspace_basis_with_width(&constraints, width)
}

fn symplectic_width(code: &StabilizerCode) -> Result<usize> {
    let n = code.n();
    n.checked_mul(2)
        .ok_or(QecError::UnsupportedExhaustiveEnumeration { n })
}