use super::*;
use crate::photonic::qec::{PlanarSurgery, SurgeryAttempt};
use crate::photonic::runtime::shot_seed;
use crate::photonic::stabilizer::Tableau;
use crate::{Error, Result};
#[derive(Clone, Copy, Debug)]
pub struct SixRingSurgeryLimits {
pub max_rings: usize,
pub max_checks: usize,
}
impl Default for SixRingSurgeryLimits {
fn default() -> Self {
Self {
max_rings: 1 << 20,
max_checks: 1 << 18,
}
}
}
#[derive(Clone, Debug)]
pub struct SixRingSurgery {
surgery: PlanarSurgery,
rings: usize,
}
#[derive(Clone, Debug)]
pub struct OpticalSurgeryRun {
pub logical: Result<SurgeryAttempt>,
pub checks: Vec<OpticalCheckAttempt>,
pub cost: OpticalSurgeryCost,
pub log_herald_weight: Option<f64>,
}
impl SixRingSurgery {
pub fn compile(surgery: &PlanarSurgery, limits: SixRingSurgeryLimits) -> Result<Self> {
let per_round = surgery
.merged_checks()
.iter()
.chain(surgery.split_checks())
.try_fold(0usize, |sum, p| {
let w = p.terms().len();
if !(1..=6).contains(&w) {
return Err(Error::Unsupported(
"six-ring lowering requires weight 1..=6 checks".into(),
));
}
sum.checked_add(w).ok_or(Error::Overflow)
})?;
let rings = per_round
.checked_mul(surgery.code().distance())
.ok_or(Error::Overflow)?;
for (resource, required, limit) in [
("six-ring surgery resources", rings, limits.max_rings),
(
"six-ring surgery check records",
surgery.measurements(),
limits.max_checks,
),
] {
if required > limit {
return Err(Error::ResourceLimit {
resource,
required,
limit,
});
}
}
rings.checked_mul(64).ok_or(Error::Overflow)?;
Ok(Self {
surgery: surgery.clone(),
rings,
})
}
pub fn scheduled_rings(&self) -> usize {
self.rings
}
pub fn scheduled_checks(&self) -> usize {
self.surgery.measurements()
}
pub fn ideal_log_herald_probability(&self) -> f64 {
-(self.rings as f64) * 4f64.ln()
}
pub fn execute(
&self,
state: &mut Tableau,
offsets: [usize; 2],
workspace: [usize; 7],
instrument: SixRingCheckInstrument,
sampling: SixRingSampling,
seed: u64,
) -> Result<OpticalSurgeryRun> {
instrument.validate_sampling(sampling)?;
let n = self.surgery.code().qubits();
let ends = offsets.map(|o| o.checked_add(n).ok_or(Error::Overflow));
let [a, b] = ends;
let ends = [a?, b?];
if offsets[0].abs_diff(offsets[1]) < n
|| ends.iter().any(|&end| end > state.qubits())
|| workspace.iter().enumerate().any(|(i, &q)| {
q >= state.qubits()
|| workspace[..i].contains(&q)
|| (0..2).any(|j| (offsets[j]..ends[j]).contains(&q))
})
{
return Err(Error::Wires(
"invalid optical surgery data/scratch layout".into(),
));
}
let mut checks = Vec::with_capacity(self.scheduled_checks());
let mut cost = OpticalSurgeryCost::default();
let logical = self.surgery.execute_with(state, offsets, |state, request| {
let record = instrument.measure(
state,
&request.observable,
workspace,
sampling,
shot_seed(seed, checks.len() as u64, 0x5355_5247_4552_0001),
)?;
let measurement = record.measurement;
cost.add(record.cost);
checks.push(record);
Ok(measurement)
});
let log_herald_weight = (sampling == SixRingSampling::ConditionedReference)
.then_some(-(cost.rings_emitted as f64) * 4f64.ln());
Ok(OpticalSurgeryRun {
logical,
checks,
cost,
log_herald_weight,
})
}
}