use super::Circuit;
use super::fusion::fuse_circuit;
use super::parameter::Parameters;
use super::plan::FusionPlan;
use crate::error::Result;
use crate::sim::{BackendKind, PreparedRoute, RunOutcome, prepared_route};
pub struct PreparedCircuit {
template: Circuit,
params: Parameters,
kind: BackendKind,
plan: Option<FusionPlan>,
route: Option<PreparedRoute>,
skeleton: Circuit,
bound: Circuit,
fused: Circuit,
fused_off_plan: bool,
}
impl Clone for PreparedCircuit {
fn clone(&self) -> Self {
Self {
template: self.template.clone(),
params: self.params.clone(),
kind: self.kind.clone(),
plan: self.plan.clone(),
route: prepared_route(&self.kind, &self.template),
skeleton: self.skeleton.clone(),
bound: self.bound.clone(),
fused: self.fused.clone(),
fused_off_plan: self.fused_off_plan,
}
}
}
impl PreparedCircuit {
pub fn new(template: Circuit, params: Parameters) -> Result<Self> {
Self::with_backend(template, params, BackendKind::Auto)
}
pub fn with_backend(template: Circuit, params: Parameters, kind: BackendKind) -> Result<Self> {
params.validate(&template)?;
let (skeleton, plan) = FusionPlan::capture(&template);
let route = prepared_route(&kind, &template);
let bound = template.clone();
let fused = skeleton.clone();
Ok(Self {
template,
params,
kind,
plan,
route,
skeleton,
bound,
fused,
fused_off_plan: false,
})
}
pub fn template(&self) -> &Circuit {
&self.template
}
pub fn parameters(&self) -> &Parameters {
&self.params
}
pub fn reuses_fusion_plan(&self) -> bool {
self.plan.is_some()
}
pub fn bind(&mut self, values: &[f64]) -> Result<&Circuit> {
self.params.check_values(values)?;
self.params.write_angles(&mut self.bound, values);
Ok(&self.bound)
}
pub fn bind_fused(&mut self, values: &[f64]) -> Result<&Circuit> {
self.params.check_values(values)?;
self.params.write_angles(&mut self.bound, values);
if let Some(plan) = &self.plan {
if self.fused_off_plan {
self.fused.clone_from(&self.skeleton);
self.fused_off_plan = false;
}
if plan.replay(&self.bound, &mut self.fused) {
return Ok(&self.fused);
}
self.fused_off_plan = true;
}
self.fused = fuse_circuit(&self.bound, true).into_owned();
Ok(&self.fused)
}
pub fn run(&mut self, values: &[f64], seed: u64) -> Result<RunOutcome> {
let fused = self
.route
.as_ref()
.is_some_and(PreparedRoute::supports_fused);
if fused {
self.bind_fused(values)?;
} else {
self.bind(values)?;
}
let Self {
kind,
route,
bound,
fused: fused_circuit,
..
} = self;
let circuit = if fused { &*fused_circuit } else { &*bound };
match route {
Some(route) => route.run(circuit, seed),
None => crate::sim::simulate(circuit)
.backend(kind.clone())
.seed(seed)
.run(),
}
}
}