1use crate::types::{Complex, QubitIndex};
4use std::f64::consts::FRAC_1_SQRT_2;
5
6#[derive(Debug, Clone)]
8pub enum Gate {
9 H(QubitIndex),
11 X(QubitIndex),
12 Y(QubitIndex),
13 Z(QubitIndex),
14 S(QubitIndex),
15 Sdg(QubitIndex),
16 T(QubitIndex),
17 Tdg(QubitIndex),
18 Rx(QubitIndex, f64),
19 Ry(QubitIndex, f64),
20 Rz(QubitIndex, f64),
21 Phase(QubitIndex, f64),
22
23 CNOT(QubitIndex, QubitIndex),
25 CZ(QubitIndex, QubitIndex),
26 SWAP(QubitIndex, QubitIndex),
27 Rzz(QubitIndex, QubitIndex, f64),
28
29 Measure(QubitIndex),
31 Reset(QubitIndex),
32 Barrier,
33
34 Unitary1Q(QubitIndex, [[Complex; 2]; 2]),
36}
37
38impl Gate {
39 pub fn qubits(&self) -> Vec<QubitIndex> {
41 match self {
42 Gate::H(q)
43 | Gate::X(q)
44 | Gate::Y(q)
45 | Gate::Z(q)
46 | Gate::S(q)
47 | Gate::Sdg(q)
48 | Gate::T(q)
49 | Gate::Tdg(q)
50 | Gate::Rx(q, _)
51 | Gate::Ry(q, _)
52 | Gate::Rz(q, _)
53 | Gate::Phase(q, _)
54 | Gate::Measure(q)
55 | Gate::Reset(q)
56 | Gate::Unitary1Q(q, _) => vec![*q],
57
58 Gate::CNOT(q1, q2)
59 | Gate::CZ(q1, q2)
60 | Gate::SWAP(q1, q2)
61 | Gate::Rzz(q1, q2, _) => vec![*q1, *q2],
62
63 Gate::Barrier => vec![],
64 }
65 }
66
67 pub fn is_non_unitary(&self) -> bool {
69 matches!(self, Gate::Measure(_) | Gate::Reset(_) | Gate::Barrier)
70 }
71
72 pub fn matrix_1q(&self) -> Option<[[Complex; 2]; 2]> {
74 let c0 = Complex::ZERO;
75 let c1 = Complex::ONE;
76 let ci = Complex::I;
77
78 match self {
79 Gate::H(_) => {
81 let h = Complex::new(FRAC_1_SQRT_2, 0.0);
82 Some([[h, h], [h, -h]])
83 }
84
85 Gate::X(_) => Some([[c0, c1], [c1, c0]]),
87
88 Gate::Y(_) => Some([[c0, -ci], [ci, c0]]),
90
91 Gate::Z(_) => Some([[c1, c0], [c0, -c1]]),
93
94 Gate::S(_) => Some([[c1, c0], [c0, ci]]),
96
97 Gate::Sdg(_) => Some([[c1, c0], [c0, -ci]]),
99
100 Gate::T(_) => {
102 let t = Complex::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2);
103 Some([[c1, c0], [c0, t]])
104 }
105
106 Gate::Tdg(_) => {
108 let t = Complex::new(FRAC_1_SQRT_2, -FRAC_1_SQRT_2);
109 Some([[c1, c0], [c0, t]])
110 }
111
112 Gate::Rx(_, theta) => {
114 let half = *theta / 2.0;
115 let c = Complex::new(half.cos(), 0.0);
116 let s = Complex::new(0.0, -half.sin());
117 Some([[c, s], [s, c]])
118 }
119
120 Gate::Ry(_, theta) => {
122 let half = *theta / 2.0;
123 let cos_h = half.cos();
124 let sin_h = half.sin();
125 Some([
126 [Complex::new(cos_h, 0.0), Complex::new(-sin_h, 0.0)],
127 [Complex::new(sin_h, 0.0), Complex::new(cos_h, 0.0)],
128 ])
129 }
130
131 Gate::Rz(_, theta) => {
133 let half = *theta / 2.0;
134 Some([
135 [Complex::from_polar(1.0, -half), c0],
136 [c0, Complex::from_polar(1.0, half)],
137 ])
138 }
139
140 Gate::Phase(_, theta) => Some([
142 [c1, c0],
143 [c0, Complex::from_polar(1.0, *theta)],
144 ]),
145
146 Gate::Unitary1Q(_, m) => Some(*m),
148
149 _ => None,
151 }
152 }
153
154 pub fn matrix_2q(&self) -> Option<[[Complex; 4]; 4]> {
159 let c0 = Complex::ZERO;
160 let c1 = Complex::ONE;
161
162 match self {
163 Gate::CNOT(_, _) => Some([
166 [c1, c0, c0, c0],
167 [c0, c1, c0, c0],
168 [c0, c0, c0, c1],
169 [c0, c0, c1, c0],
170 ]),
171
172 Gate::CZ(_, _) => Some([
174 [c1, c0, c0, c0],
175 [c0, c1, c0, c0],
176 [c0, c0, c1, c0],
177 [c0, c0, c0, -c1],
178 ]),
179
180 Gate::SWAP(_, _) => Some([
182 [c1, c0, c0, c0],
183 [c0, c0, c1, c0],
184 [c0, c1, c0, c0],
185 [c0, c0, c0, c1],
186 ]),
187
188 Gate::Rzz(_, _, theta) => {
190 let half = *theta / 2.0;
191 let en = Complex::from_polar(1.0, -half);
192 let ep = Complex::from_polar(1.0, half);
193 Some([
194 [en, c0, c0, c0],
195 [c0, ep, c0, c0],
196 [c0, c0, ep, c0],
197 [c0, c0, c0, en],
198 ])
199 }
200
201 _ => None,
202 }
203 }
204}