qvnt/operator/atomic/
u1.rs

1use super::*;
2use crate::math::matrix::{inverse_unitary_m1, is_unitary_m1};
3
4#[derive(Clone, Copy, PartialEq)]
5pub struct Op {
6    a_mask: N,
7    matrix: M1,
8}
9
10impl Op {
11    pub fn new(a_mask: N, matrix: M1) -> Self {
12        Self { a_mask, matrix }
13    }
14}
15
16impl AtomicOp for Op {
17    fn atomic_op(&self, psi: &[C], idx: N) -> C {
18        let a_bit = (idx & self.a_mask) != 0;
19        let idx = idx & !self.a_mask;
20        if !a_bit {
21            self.matrix[0b00] * psi[idx] + self.matrix[0b01] * psi[idx | self.a_mask]
22        } else {
23            self.matrix[0b10] * psi[idx] + self.matrix[0b11] * psi[idx | self.a_mask]
24        }
25    }
26
27    fn name(&self) -> String {
28        format!(
29            "U{}{:?}",
30            self.a_mask,
31            [&self.matrix[..2], &self.matrix[2..]]
32        )
33    }
34
35    fn is_valid(&self) -> bool {
36        self.a_mask.count_ones() == 1 && is_unitary_m1(&self.matrix)
37    }
38
39    fn acts_on(&self) -> N {
40        self.a_mask
41    }
42
43    fn this(self) -> dispatch::AtomicOpDispatch {
44        dispatch::AtomicOpDispatch::U1(self)
45    }
46
47    fn dgr(self) -> dispatch::AtomicOpDispatch {
48        dispatch::AtomicOpDispatch::U1(Self {
49            matrix: inverse_unitary_m1(&self.matrix),
50            ..self
51        })
52    }
53}
54
55#[cfg(test)]
56#[test]
57fn matrix_repr() {
58    use crate::operator::single::*;
59
60    const O: C = C { re: 0.0, im: 0.0 };
61    const I: C = C { re: 1.0, im: 0.0 };
62    const SQRT_1_2: C = C {
63        re: FRAC_1_SQRT_2,
64        im: 0.0,
65    };
66
67    let op = Op::new(0b1, [I, O, O, I]);
68    assert!(op.is_valid());
69
70    let op: SingleOp = op.into();
71    assert_eq!(op.name(), format!("U1[[{I:?}, {O:?}], [{O:?}, {I:?}]]"));
72    assert_eq!(op.matrix(1), [[I, O], [O, I]]);
73
74    let op = Op::new(0b1, [I, I, O, I]);
75    assert!(!op.is_valid());
76
77    let op = Op::new(0b11, [I, O, O, I]);
78    assert!(!op.is_valid());
79
80    let op = Op::new(0b1, [SQRT_1_2, SQRT_1_2, SQRT_1_2, -SQRT_1_2]);
81    assert!(op.is_valid());
82
83    let op: SingleOp = op.into();
84    assert_eq!(
85        op.name(),
86        format!(
87            "U1[[{SQRT_1_2:?}, {SQRT_1_2:?}], [{SQRT_1_2:?}, {:?}]]",
88            -SQRT_1_2
89        )
90    );
91    assert_eq!(op.matrix(1), [[SQRT_1_2, SQRT_1_2], [SQRT_1_2, -SQRT_1_2]]);
92}