qvnt 0.5.0-alpha

Advanced quantum computation simulator.
Documentation
use super::*;

#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Op {
    a_mask: Mask,
    b_mask: Mask,
    ab_mask: Mask,
}

impl Op {
    #[inline(always)]
    pub fn new(a_mask: Mask, b_mask: Mask) -> Self {
        Self {
            a_mask,
            b_mask,
            ab_mask: a_mask | b_mask,
        }
    }
}

impl crate::sealed::Seal for Op {}

impl super::NativeCpuOp for Op {
    #[inline(always)]
    fn native_cpu_op(&self, psi: &[C], idx: Mask) -> C {
        let mut psi = (
            psi[idx],
            psi[idx ^ self.a_mask],
            psi[idx ^ self.b_mask],
            psi[idx ^ self.ab_mask],
        );
        if idx & self.a_mask != 0 {
            psi.0 = -psi.0;
            psi.2 = -psi.2;
        }
        if idx & self.b_mask != 0 {
            psi.0 = -psi.0;
            psi.1 = -psi.1;
        }
        (psi.0 + psi.1 + psi.2 + psi.3).scale(0.5)
    }
}

impl AtomicOp for Op {
    fn name(&self) -> String {
        format!("H{}", self.a_mask | self.b_mask)
    }

    fn is_valid(&self) -> bool {
        self.a_mask.count_ones() == 1
            && self.b_mask.count_ones() == 1
            && self.ab_mask.count_ones() == 2
    }

    fn acts_on(&self) -> Mask {
        self.ab_mask
    }

    fn this(self) -> AtomicOpDispatch {
        AtomicOpDispatch::H2(self)
    }

    fn dgr(self) -> AtomicOpDispatch {
        AtomicOpDispatch::H2(self)
    }
}

#[cfg(test)]
#[test]
fn matrix_repr() {
    use crate::operator::single::*;

    const O_5: C = C { re: 0.5, im: 0.0 };

    let op: SingleOp = Op::new(0b01, 0b10).into();
    assert_eq!(op.name(), "H3");
    assert_eq!(
        op.matrix(2),
        [
            [O_5, O_5, O_5, O_5],
            [O_5, -O_5, O_5, -O_5],
            [O_5, O_5, -O_5, -O_5],
            [O_5, -O_5, -O_5, O_5]
        ]
    );
}