pub use crate::linalg::C;
#[derive(Clone, Debug)]
pub struct Gate {
pub qubits: Vec<u32>,
pub matrix: Vec<C>,
}
pub fn complex(re: f64, im: f64) -> C {
C { re, im }
}
const Z: C = C { re: 0.0, im: 0.0 };
const O: C = C { re: 1.0, im: 0.0 };
const I: C = C { re: 0.0, im: 1.0 };
fn cis(theta: f64) -> C {
let (s, c) = crate::repro::sin_cos(theta);
C { re: c, im: s }
}
fn one(q: u32, m: [C; 4]) -> Gate {
Gate { qubits: vec![q], matrix: m.to_vec() }
}
fn two(a: u32, b: u32, m: [C; 16]) -> Gate {
Gate { qubits: vec![a, b], matrix: m.to_vec() }
}
impl Gate {
pub fn h(q: u32) -> Gate {
let r = core::f64::consts::FRAC_1_SQRT_2;
one(q, [complex(r, 0.0), complex(r, 0.0), complex(r, 0.0), complex(-r, 0.0)])
}
pub fn x(q: u32) -> Gate {
one(q, [Z, O, O, Z])
}
pub fn y(q: u32) -> Gate {
one(q, [Z, complex(0.0, -1.0), I, Z])
}
pub fn z(q: u32) -> Gate {
one(q, [O, Z, Z, complex(-1.0, 0.0)])
}
pub fn s(q: u32) -> Gate {
one(q, [O, Z, Z, I])
}
pub fn sdg(q: u32) -> Gate {
one(q, [O, Z, Z, complex(0.0, -1.0)])
}
pub fn t(q: u32) -> Gate {
let r = core::f64::consts::FRAC_1_SQRT_2;
one(q, [O, Z, Z, complex(r, r)])
}
pub fn tdg(q: u32) -> Gate {
let r = core::f64::consts::FRAC_1_SQRT_2;
one(q, [O, Z, Z, complex(r, -r)])
}
pub fn sqrt_x(q: u32) -> Gate {
let (p, m) = (complex(0.5, 0.5), complex(0.5, -0.5));
one(q, [p, m, m, p])
}
pub fn sqrt_y(q: u32) -> Gate {
let p = complex(0.5, 0.5);
one(q, [p, complex(-0.5, -0.5), p, p])
}
pub fn sqrt_w(q: u32) -> Gate {
let (p, m) = (complex(0.5, 0.5), complex(0.5, -0.5));
let (e, ec) = (cis(core::f64::consts::FRAC_PI_4), cis(-core::f64::consts::FRAC_PI_4));
let mul = |a: C, b: C| complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
one(q, [p, mul(m, ec), mul(m, e), p])
}
pub fn rx(q: u32, theta: f64) -> Gate {
let (s, c) = crate::repro::sin_cos(theta / 2.0);
one(q, [complex(c, 0.0), complex(0.0, -s), complex(0.0, -s), complex(c, 0.0)])
}
pub fn ry(q: u32, theta: f64) -> Gate {
let (s, c) = crate::repro::sin_cos(theta / 2.0);
one(q, [complex(c, 0.0), complex(-s, 0.0), complex(s, 0.0), complex(c, 0.0)])
}
pub fn rz(q: u32, theta: f64) -> Gate {
one(q, [cis(-theta / 2.0), Z, Z, cis(theta / 2.0)])
}
pub fn phase(q: u32, theta: f64) -> Gate {
one(q, [O, Z, Z, cis(theta)])
}
pub fn cx(c: u32, t: u32) -> Gate {
two(c, t, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, Z, O, Z, Z, O, Z])
}
pub fn cz(a: u32, b: u32) -> Gate {
two(a, b, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, O, Z, Z, Z, Z, complex(-1.0, 0.0)])
}
pub fn swap(a: u32, b: u32) -> Gate {
two(a, b, [O, Z, Z, Z, Z, Z, O, Z, Z, O, Z, Z, Z, Z, Z, O])
}
pub fn iswap(a: u32, b: u32) -> Gate {
two(a, b, [O, Z, Z, Z, Z, Z, I, Z, Z, I, Z, Z, Z, Z, Z, O])
}
pub fn cphase(a: u32, b: u32, phi: f64) -> Gate {
two(a, b, [O, Z, Z, Z, Z, O, Z, Z, Z, Z, O, Z, Z, Z, Z, cis(phi)])
}
pub fn rzz(a: u32, b: u32, theta: f64) -> Gate {
let (m, p) = (cis(-theta / 2.0), cis(theta / 2.0));
two(a, b, [m, Z, Z, Z, Z, p, Z, Z, Z, Z, p, Z, Z, Z, Z, m])
}
pub fn fsim(a: u32, b: u32, theta: f64, phi: f64) -> Gate {
let (s, c) = crate::repro::sin_cos(theta);
let (cc, ms) = (complex(c, 0.0), complex(0.0, -s));
two(a, b, [O, Z, Z, Z, Z, cc, ms, Z, Z, ms, cc, Z, Z, Z, Z, cis(-phi)])
}
pub fn is_diagonal(&self) -> bool {
let d = 1usize << self.qubits.len();
(0..d).all(|r| (0..d).all(|c| r == c || (self.matrix[r * d + c].re == 0.0 && self.matrix[r * d + c].im == 0.0)))
}
}