qec-code 0.3.0

Rust primitives for constructing and analyzing quantum error-correcting codes
Documentation
use qec_code::codes::steane::Steane;
use qec_code::distance::compute_distance;
use qec_code::logical::extract_logical_basis;
use qec_code::{Pauli, QecError, StabilizerCode};

fn pauli(n: usize, x_support: &[usize], z_support: &[usize]) -> Pauli {
    let mut x = vec![0; n];
    let mut z = vec![0; n];
    for &qubit in x_support {
        x[qubit] = 1;
    }
    for &qubit in z_support {
        z[qubit] = 1;
    }
    Pauli::from_xz_bits(x, z).unwrap()
}

#[test]
fn steane_logical_basis_contains_one_anticommuting_pair() {
    let steane = Steane::new().unwrap();
    let code = steane.code();

    let basis = extract_logical_basis(code).unwrap();

    assert_eq!(basis.k, 1);
    assert_eq!(basis.logical_x.len(), 1);
    assert_eq!(basis.logical_z.len(), 1);
    assert!(basis.logical_x[0].anticommutes_with(&basis.logical_z[0]));

    for stabilizer in code.stabilizers() {
        assert!(basis.logical_x[0].commutes_with(stabilizer));
        assert!(basis.logical_z[0].commutes_with(stabilizer));
    }
}

#[test]
fn steane_distance_is_three_with_a_commuting_weight_three_witness() {
    let steane = Steane::new().unwrap();
    let code = steane.code();

    let distance = compute_distance(code).unwrap();

    assert_eq!(distance.distance, 3);
    assert_eq!(distance.witness.weight(), 3);

    for stabilizer in code.stabilizers() {
        assert!(distance.witness.commutes_with(stabilizer));
    }
}

#[test]
fn logical_basis_supports_multi_logical_codes() {
    let code = StabilizerCode::from_stabilizers(4, vec![pauli(4, &[], &[0]), pauli(4, &[], &[1])])
        .unwrap();

    let basis = extract_logical_basis(&code).unwrap();

    assert_eq!(basis.k, 2);
    assert_eq!(basis.logical_x.len(), 2);
    assert_eq!(basis.logical_z.len(), 2);
    for index in 0..basis.k {
        assert!(basis.logical_x[index].anticommutes_with(&basis.logical_z[index]));
    }
    for stabilizer in code.stabilizers() {
        for logical in basis.logical_x.iter().chain(&basis.logical_z) {
            assert!(logical.commutes_with(stabilizer));
        }
    }
}

#[test]
fn logical_basis_for_zero_logical_qubits_is_empty() {
    let code =
        StabilizerCode::from_stabilizers(1, vec![Pauli::from_xz_bits(vec![1], vec![0]).unwrap()])
            .unwrap();

    let basis = extract_logical_basis(&code).unwrap();

    assert_eq!(basis.k, 0);
    assert!(basis.logical_x.is_empty());
    assert!(basis.logical_z.is_empty());
}

#[test]
fn distance_returns_no_witness_for_zero_logical_qubit_code() {
    let code = StabilizerCode::from_stabilizers(
        2,
        vec![
            Pauli::from_xz_bits(vec![1, 0], vec![0, 0]).unwrap(),
            Pauli::from_xz_bits(vec![0, 0], vec![0, 1]).unwrap(),
        ],
    )
    .unwrap();

    assert_eq!(
        compute_distance(&code),
        Err(QecError::DistanceWitnessNotFound)
    );
}

#[test]
fn large_code_logical_basis_avoids_exhaustive_enumeration() {
    let stabilizers = (0..31)
        .map(|qubit| {
            let mut z = vec![0; 32];
            z[qubit] = 1;
            Pauli::from_xz_bits(vec![0; 32], z).unwrap()
        })
        .collect();
    let code = StabilizerCode::from_stabilizers(32, stabilizers).unwrap();

    let basis = extract_logical_basis(&code).unwrap();

    assert_eq!(basis.k, 1);
    assert_eq!(basis.logical_x.len(), 1);
    assert_eq!(basis.logical_z.len(), 1);
    assert!(basis.logical_x[0].anticommutes_with(&basis.logical_z[0]));
    for stabilizer in code.stabilizers() {
        assert!(basis.logical_x[0].commutes_with(stabilizer));
        assert!(basis.logical_z[0].commutes_with(stabilizer));
    }
    #[cfg(not(feature = "distance-ilp-highs"))]
    assert_eq!(
        compute_distance(&code),
        Err(QecError::DistanceComputationUnsupported {
            n: 32,
            reason: "enable a distance ILP feature or use a smaller code".into(),
        })
    );
}

#[cfg(feature = "distance-ilp-highs")]
#[test]
fn steane_distance_matches_ilp_path() {
    let steane = Steane::new().unwrap();

    let distance = compute_distance(steane.code()).unwrap();

    assert_eq!(distance.distance, 3);
    assert_eq!(distance.witness.weight(), 3);
}

#[cfg(feature = "distance-ilp-highs")]
#[test]
fn multi_logical_code_returns_a_nontrivial_minimum_witness() {
    let code = StabilizerCode::from_stabilizers(4, vec![pauli(4, &[], &[0]), pauli(4, &[], &[1])])
        .unwrap();

    let distance = compute_distance(&code).unwrap();

    assert_eq!(distance.distance, 1);
    assert_eq!(distance.witness.weight(), 1);
    assert!(
        !distance
            .witness
            .x_bits()
            .iter()
            .chain(distance.witness.z_bits())
            .all(|&bit| bit == 0)
    );
}

#[cfg(not(feature = "distance-ilp-highs"))]
#[test]
fn large_code_without_ilp_reports_configuration_specific_unsupported_error() {
    let stabilizers = (0..31)
        .map(|qubit| {
            let mut z = vec![0; 32];
            z[qubit] = 1;
            Pauli::from_xz_bits(vec![0; 32], z).unwrap()
        })
        .collect();
    let code = StabilizerCode::from_stabilizers(32, stabilizers).unwrap();

    let err = compute_distance(&code).unwrap_err();

    assert_eq!(
        err,
        QecError::DistanceComputationUnsupported {
            n: 32,
            reason: "enable a distance ILP feature or use a smaller code".into(),
        }
    );
}