use super::{probability, Circuit, Error, Result};
use crate::memory::{CodeKind, NoiseModel};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Basis {
X,
Z,
}
impl Basis {
pub(crate) fn engine(self) -> crate::circuit::Basis {
match self {
Basis::X => crate::circuit::Basis::X,
Basis::Z => crate::circuit::Basis::Z,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum SurfaceCode {
Rotated,
Xzzx,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum Noise {
Sd6 {
p: f64,
},
Biased {
p: f64,
eta: f64,
},
}
pub fn memory_circuit(code: SurfaceCode, distance: usize, rounds: usize, noise: Noise, basis: Basis) -> Result<Circuit> {
let kind = match code {
SurfaceCode::Rotated => CodeKind::Rotated,
SurfaceCode::Xzzx => CodeKind::Xzzx,
};
let noise = match noise {
Noise::Sd6 { p } => NoiseModel::Sd6 { p },
Noise::Biased { p, eta } => NoiseModel::Current { p, eta },
};
Circuit::from_engine(crate::memory::generate(kind, distance, rounds, noise, basis.engine())?)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum GrossOperator {
F,
Gh,
FTimesGh,
}
#[derive(Clone, Debug)]
pub struct BivariateBicycleCode {
inner: crate::bb::BbCode,
gross: bool,
}
impl BivariateBicycleCode {
pub fn gross() -> BivariateBicycleCode {
BivariateBicycleCode { inner: crate::bb::BbCode::gross(), gross: true }
}
pub fn bb72() -> BivariateBicycleCode {
BivariateBicycleCode { inner: crate::bb::BbCode::bb72(), gross: false }
}
pub fn n(&self) -> usize {
2 * self.inner.l * self.inner.m
}
pub fn k(&self) -> usize {
self.inner.logicals().0.rows
}
pub fn check_matrices(&self) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
let rows = |m: &crate::gf2::BitMatrix| (0..m.rows).map(|r| m.row_ones(r)).collect();
(rows(&self.inner.hx()), rows(&self.inner.hz()))
}
pub fn logicals(&self) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
let (lx, lz) = self.inner.logicals();
let rows = |m: &crate::gf2::BitMatrix| (0..m.rows).map(|r| m.row_ones(r)).collect();
(rows(&lx), rows(&lz))
}
pub fn memory_circuit(&self, cycles: usize, p: f64, basis: Basis) -> Result<Circuit> {
crate::bb::check_cycles(cycles, cycles)?;
probability(p, "p")?;
let c = match basis {
Basis::Z => crate::circuit::Circuit::parse(&self.inner.memory_z(cycles, p))?,
Basis::X => crate::bb_circuit::memory(&self.inner, basis.engine(), cycles, p),
};
Circuit::from_engine(c)
}
#[allow(clippy::too_many_arguments)]
pub fn logical_measurement_circuit(
&self,
operator: GrossOperator,
basis: Basis,
pre: usize,
merged: usize,
post: usize,
p: f64,
expanded: bool,
) -> Result<Circuit> {
if !self.gross {
return Err(Error::new("logical measurements are built for the gross code only"));
}
crate::bb::check_cycles(pre.saturating_add(merged).saturating_add(post).max(1), merged)?;
probability(p, "p")?;
let name = match operator {
GrossOperator::F => "f",
GrossOperator::Gh => "gh",
GrossOperator::FTimesGh => "f+gh",
};
let support = crate::bb::gross_operator(name)?;
let g = if expanded {
crate::bb_gauge::Gauging::expanded(&self.inner, &support)
} else {
crate::bb_gauge::Gauging::new(&self.inner, &support)
}?;
Circuit::from_engine(crate::bb_circuit::logical_measurement(&self.inner, &g, basis.engine(), pre, merged, post, p)?)
}
}