mod density_matrix;
mod stabilizer;
mod statevector;
pub use density_matrix::{DensityMatrixBackend, DensityMatrixExecution};
pub use stabilizer::{PauliString, StabilizerBackend, StabilizerExecution};
pub use statevector::{Execution, StateVectorBackend};
use crate::gate::{Gate1, Gate2};
use crate::op::Op;
pub trait Backend {
fn apply_1q(&mut self, gate: &Gate1, target: usize);
fn apply_2q(&mut self, gate: &Gate2, a: usize, b: usize);
fn apply_controlled(&mut self, controls: &[usize], gate: &Gate1, target: usize);
fn measure(&mut self, qubit: usize) -> bool;
}
pub(crate) fn drive<B: Backend>(backend: &mut B, ops: &[Op], num_classical: usize) -> Vec<bool> {
let mut classical = vec![false; num_classical];
for op in ops {
apply_op(backend, op, &mut classical);
}
classical
}
fn apply_op<B: Backend>(backend: &mut B, op: &Op, classical: &mut [bool]) {
match op {
Op::Apply1 { gate, target } => backend.apply_1q(gate, target.index()),
Op::Apply2 { gate, a, b } => backend.apply_2q(gate, a.index(), b.index()),
Op::Controlled {
controls,
gate,
target,
} => {
let cs: Vec<usize> = controls.iter().map(|q| q.index()).collect();
backend.apply_controlled(&cs, gate, target.index());
}
Op::Measure { qubit, into } => {
classical[into.index()] = backend.measure(qubit.index());
}
Op::IfClassic { bit, then } => {
if classical[bit.index()] {
apply_op(backend, then, classical);
}
}
}
}