qvnt/operator/atomic/
u1.rs1use 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}