use crate::{Qubit, UnitaryBuilder};
use num::Complex;
pub fn chain<B: UnitaryBuilder>(b: &mut B, q: Qubit) -> SingleQubitChain<B> {
SingleQubitChain::new(b, q)
}
pub fn chain_tuple<B: UnitaryBuilder>(b: &mut B, qa: Qubit, qb: Qubit) -> DoubleQubitChain<B> {
DoubleQubitChain::new(b, qa, qb)
}
pub fn chain_vec<B: UnitaryBuilder>(b: &mut B, qs: Vec<Qubit>) -> VecQubitChain<B> {
VecQubitChain::new(b, qs)
}
#[derive(Debug)]
pub struct SingleQubitChain<'a, B: UnitaryBuilder> {
builder: &'a mut B,
q: Qubit,
}
#[derive(Debug)]
pub struct DoubleQubitChain<'a, B: UnitaryBuilder> {
builder: &'a mut B,
qa: Qubit,
qb: Qubit,
}
#[derive(Debug)]
pub struct VecQubitChain<'a, B: UnitaryBuilder> {
builder: &'a mut B,
qs: Vec<Qubit>,
}
impl<'a, B: UnitaryBuilder> SingleQubitChain<'a, B> {
pub fn new(builder: &'a mut B, q: Qubit) -> Self {
SingleQubitChain::<'a, B> { builder, q }
}
pub fn release(self) -> Qubit {
self.q()
}
pub fn q(self) -> Qubit {
self.q
}
pub fn split(self, indices: Vec<u64>) -> Result<DoubleQubitChain<'a, B>, &'static str> {
let (qa, qb) = self.builder.split(self.q, indices)?;
Ok(DoubleQubitChain::new(self.builder, qa, qb))
}
pub fn split_absolute(
self,
selected_indices: Vec<u64>,
) -> Result<DoubleQubitChain<'a, B>, &'static str> {
let (qa, qb) = self.builder.split_absolute(self.q, selected_indices)?;
Ok(DoubleQubitChain::new(self.builder, qa, qb))
}
pub fn split_all(self) -> Result<VecQubitChain<'a, B>, &'static str> {
let qs = self.builder.split_all(self.q);
Ok(VecQubitChain::new(self.builder, qs))
}
pub fn apply_mat(self, name: &str, mat: Vec<Complex<f64>>) -> Result<Self, &'static str> {
let q = self.builder.mat(name, self.q, mat)?;
Ok(Self::new(self.builder, q))
}
pub fn apply_sparse_mat(
self,
name: &str,
mat: Vec<Vec<(u64, Complex<f64>)>>,
natural_order: bool,
) -> Result<Self, &'static str> {
let q = self.builder.sparse_mat(name, self.q, mat, natural_order)?;
Ok(Self::new(self.builder, q))
}
pub fn not(self) -> Self {
let q = self.builder.not(self.q);
Self::new(self.builder, q)
}
pub fn x(self) -> Self {
let q = self.builder.x(self.q);
Self::new(self.builder, q)
}
pub fn y(self) -> Self {
let q = self.builder.y(self.q);
Self::new(self.builder, q)
}
pub fn z(self) -> Self {
let q = self.builder.z(self.q);
Self::new(self.builder, q)
}
pub fn hadamard(self) -> Self {
let q = self.builder.hadamard(self.q);
Self::new(self.builder, q)
}
pub fn apply(self, f: impl FnOnce(&mut B, Qubit) -> Qubit) -> Self {
let q = f(self.builder, self.q);
Self::new(self.builder, q)
}
pub fn apply_cut(
self,
f: impl FnOnce(&mut B, Qubit) -> (Qubit, Qubit),
) -> DoubleQubitChain<'a, B> {
let (qa, qb) = f(self.builder, self.q);
DoubleQubitChain::new(self.builder, qa, qb)
}
pub fn apply_split(self, f: impl FnOnce(&mut B, Qubit) -> Vec<Qubit>) -> VecQubitChain<'a, B> {
let qs = f(self.builder, self.q);
VecQubitChain::new(self.builder, qs)
}
}
impl<'a, B: UnitaryBuilder> DoubleQubitChain<'a, B> {
pub fn new(builder: &'a mut B, qa: Qubit, qb: Qubit) -> Self {
DoubleQubitChain::<'a, B> { builder, qa, qb }
}
pub fn release(self) -> (Qubit, Qubit) {
self.qab()
}
pub fn qab(self) -> (Qubit, Qubit) {
(self.qa, self.qb)
}
pub fn merge(self) -> SingleQubitChain<'a, B> {
let q = self.builder.merge(vec![self.qa, self.qb]);
SingleQubitChain::new(self.builder, q)
}
pub fn split_all(self) -> VecQubitChain<'a, B> {
let q = self.builder.merge(vec![self.qa, self.qb]);
let qs = self.builder.split_all(q);
VecQubitChain::new(self.builder, qs)
}
pub fn swap(self) -> Result<Self, &'static str> {
let (qa, qb) = self.builder.swap(self.qa, self.qb)?;
Ok(Self::new(self.builder, qa, qb))
}
pub fn physical_swap(self) -> Self {
Self::new(self.builder, self.qb, self.qa)
}
pub fn apply_function_op(
self,
f: impl Fn(u64) -> (u64, f64) + Send + Sync + 'static,
) -> Result<Self, &'static str> {
let (qa, qb) = self.builder.apply_function(self.qa, self.qb, Box::new(f))?;
Ok(Self::new(self.builder, qa, qb))
}
pub fn apply_boxed_function_op(
self,
f: Box<Fn(u64) -> (u64, f64) + Send + Sync>,
) -> Result<Self, &'static str> {
let (qa, qb) = self.builder.apply_function(self.qa, self.qb, f)?;
Ok(Self::new(self.builder, qa, qb))
}
pub fn apply_merge(
self,
f: impl FnOnce(&mut B, Qubit, Qubit) -> Qubit,
) -> SingleQubitChain<'a, B> {
let q = f(self.builder, self.qa, self.qb);
SingleQubitChain::new(self.builder, q)
}
pub fn apply(self, f: impl FnOnce(&mut B, Qubit, Qubit) -> (Qubit, Qubit)) -> Self {
let (qa, qb) = f(self.builder, self.qa, self.qb);
Self::new(self.builder, qa, qb)
}
pub fn apply_split(
self,
f: impl FnOnce(&mut B, Qubit, Qubit) -> Vec<Qubit>,
) -> VecQubitChain<'a, B> {
let qs = f(self.builder, self.qa, self.qb);
VecQubitChain::new(self.builder, qs)
}
}
impl<'a, B: UnitaryBuilder> VecQubitChain<'a, B> {
pub fn new(builder: &'a mut B, qs: Vec<Qubit>) -> Self {
VecQubitChain::<'a, B> { builder, qs }
}
pub fn release(self) -> Vec<Qubit> {
self.qs()
}
pub fn qs(self) -> Vec<Qubit> {
self.qs
}
pub fn merge(self) -> SingleQubitChain<'a, B> {
let q = self.builder.merge(self.qs);
SingleQubitChain::new(self.builder, q)
}
pub fn partition_by_relative(
self,
f: impl Fn(u64) -> bool,
) -> Result<DoubleQubitChain<'a, B>, &'static str> {
let (a, b): (Vec<_>, Vec<_>) = self
.qs
.into_iter()
.enumerate()
.partition(|(i, _)| f(*i as u64));
if a.is_empty() {
Err("Partition must provide at least one qubit to first entry.")
} else if b.is_empty() {
Err("Partition must provide at least one qubit to second entry.")
} else {
let f = |vs: Vec<(usize, Qubit)>| -> Vec<Qubit> {
vs.into_iter().map(|(_, q)| q).collect()
};
let qa = self.builder.merge(f(a));
let qb = self.builder.merge(f(b));
Ok(DoubleQubitChain::new(self.builder, qa, qb))
}
}
pub fn flatten(self) -> Self {
let qs = self.qs;
let builder = self.builder;
let qs: Vec<_> = qs
.into_iter()
.map(|q| builder.split_all(q))
.flatten()
.collect();
Self::new(builder, qs)
}
pub fn apply_merge(
self,
f: impl FnOnce(&mut B, Vec<Qubit>) -> Qubit,
) -> SingleQubitChain<'a, B> {
let q = f(self.builder, self.qs);
SingleQubitChain::new(self.builder, q)
}
pub fn apply_partition(
self,
f: impl FnOnce(&mut B, Vec<Qubit>) -> (Qubit, Qubit),
) -> DoubleQubitChain<'a, B> {
let (qa, qb) = f(self.builder, self.qs);
DoubleQubitChain::new(self.builder, qa, qb)
}
pub fn apply(self, f: impl FnOnce(&mut B, Vec<Qubit>) -> Vec<Qubit>) -> Self {
let qs = f(self.builder, self.qs);
Self::new(self.builder, qs)
}
}