mod execution;
mod fusion_lowering;
mod lowering;
mod parity_retry;
mod physical;
mod synthesis;
use crate::{Angle, Circuit, ResourceLimits, StateVector};
use burn::tensor::Tensor;
pub use execution::PatternSimulator;
pub use fusion_lowering::{HeraldedGatePlan, TeleportationPorts};
pub use parity_retry::{ParityRetryBranch, ParityRetryPlan, ParityRetryRun};
pub use physical::PhysicalRailOptions;
pub use physical::{
CalibratedOutcome, PhysicalCalibration, PhysicalCircuit, PhysicalGate, PhysicalOutcome,
PhysicalPlacement, PhysicalRun, ResourceFactoryModel,
};
use serde::Serialize;
pub use synthesis::{GateSynthesis, SynthesisOptions};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct PatternSite(pub usize);
#[derive(Clone, Copy, Debug)]
pub struct PatternCompileLimits {
pub max_sites: usize,
pub max_commands: usize,
}
impl Default for PatternCompileLimits {
fn default() -> Self {
Self {
max_sites: 4096,
max_commands: 32768,
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Serialize)]
pub enum PatternCommand {
PreparePlus {
site: PatternSite,
},
Entangle {
sites: [PatternSite; 2],
},
Measure {
site: PatternSite,
angle: Angle,
bit: usize,
},
CorrectX {
site: PatternSite,
bit: usize,
},
}
#[derive(Clone, Debug, Serialize)]
pub struct MeasurementPattern {
version: u32,
source: Circuit,
commands: Vec<PatternCommand>,
outputs: Vec<PatternSite>,
sites: usize,
measurements: usize,
synthesis_error: f64,
}
impl MeasurementPattern {
pub fn compile(source: &Circuit, limits: PatternCompileLimits) -> crate::Result<Self> {
let synthesized = GateSynthesis::compile(
source,
SynthesisOptions {
max_native_gates: limits.max_commands,
..Default::default()
},
)?;
let mut pattern = lowering::compile(synthesized.circuit(), limits)?;
pattern.source = source.clone();
pattern.synthesis_error = synthesized.numerical_error();
Ok(pattern)
}
pub fn source(&self) -> &Circuit {
&self.source
}
pub fn commands(&self) -> &[PatternCommand] {
&self.commands
}
pub fn outputs(&self) -> &[PatternSite] {
&self.outputs
}
pub fn sites(&self) -> usize {
self.sites
}
pub fn measurements(&self) -> usize {
self.measurements
}
pub fn synthesis_error(&self) -> f64 {
self.synthesis_error
}
}
#[derive(Clone, Copy, Debug)]
pub struct PatternSimulationLimits {
pub dense: ResourceLimits,
pub max_branches: usize,
}
impl Default for PatternSimulationLimits {
fn default() -> Self {
Self {
dense: ResourceLimits::default(),
max_branches: 4096,
}
}
}
#[derive(Clone, Debug)]
pub struct PatternBranch {
pub(crate) outcomes: Vec<bool>,
pub(crate) state: StateVector,
}
impl PatternBranch {
pub fn outcomes(&self) -> &[bool] {
&self.outcomes
}
pub fn state(&self) -> &StateVector {
&self.state
}
pub fn probability(&self) -> Tensor<1> {
self.state.norm_squared()
}
pub fn conditional_state(&self, min_probability: f64) -> crate::Result<StateVector> {
crate::error::tolerance(min_probability)?;
let p = self.probability();
if crate::complex::read(p.clone())?
.iter()
.any(|v| !v.is_finite() || *v <= min_probability)
{
return Err(crate::Error::InvalidValue(
"impossible or too-small pattern branch".into(),
));
}
let scale = p.sqrt().reshape([self.state.batch_size(), 1]);
let amplitudes = crate::ComplexTensor::new(
self.state.amplitudes().real() / scale.clone(),
self.state.amplitudes().imag() / scale,
)?;
let limits = ResourceLimits {
max_state_elements: self.state.batch_size() * self.state.register().size(),
..Default::default()
};
StateVector::from_amplitudes(self.state.register().clone(), amplitudes, limits)
}
}