quantrs2_ml/torchquantum/gates/
three_qubit.rs1use super::super::{
9 CType, NParamsEnum, OpHistoryEntry, TQDevice, TQModule, TQOperator, TQParameter, WiresEnum,
10};
11use crate::error::{MLError, Result};
12use scirs2_core::ndarray::Array2;
13
14#[derive(Debug, Clone)]
16pub struct TQCSWAP {
17 inverse: bool,
18 static_mode: bool,
19}
20
21impl TQCSWAP {
22 pub fn new() -> Self {
23 Self {
24 inverse: false,
25 static_mode: false,
26 }
27 }
28}
29
30impl Default for TQCSWAP {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl TQModule for TQCSWAP {
37 fn forward(&mut self, _qdev: &mut TQDevice) -> Result<()> {
38 Err(MLError::InvalidConfiguration(
39 "Use apply() instead of forward() for operators".to_string(),
40 ))
41 }
42
43 fn parameters(&self) -> Vec<TQParameter> {
44 Vec::new()
45 }
46
47 fn n_wires(&self) -> Option<usize> {
48 Some(3)
49 }
50
51 fn set_n_wires(&mut self, _n_wires: usize) {}
52
53 fn is_static_mode(&self) -> bool {
54 self.static_mode
55 }
56
57 fn static_on(&mut self) {
58 self.static_mode = true;
59 }
60
61 fn static_off(&mut self) {
62 self.static_mode = false;
63 }
64
65 fn name(&self) -> &str {
66 "CSWAP"
67 }
68}
69
70impl TQOperator for TQCSWAP {
71 fn num_wires(&self) -> WiresEnum {
72 WiresEnum::Fixed(3)
73 }
74
75 fn num_params(&self) -> NParamsEnum {
76 NParamsEnum::Fixed(0)
77 }
78
79 fn get_matrix(&self, _params: Option<&[f64]>) -> Array2<CType> {
80 let mut matrix = Array2::eye(8).mapv(|x| CType::new(x, 0.0));
83 matrix[[5, 5]] = CType::new(0.0, 0.0);
85 matrix[[5, 6]] = CType::new(1.0, 0.0);
86 matrix[[6, 5]] = CType::new(1.0, 0.0);
87 matrix[[6, 6]] = CType::new(0.0, 0.0);
88 matrix
89 }
90
91 fn apply(&mut self, qdev: &mut TQDevice, wires: &[usize]) -> Result<()> {
92 self.apply_with_params(qdev, wires, None)
93 }
94
95 fn apply_with_params(
96 &mut self,
97 qdev: &mut TQDevice,
98 wires: &[usize],
99 _params: Option<&[f64]>,
100 ) -> Result<()> {
101 if wires.len() < 3 {
102 return Err(MLError::InvalidConfiguration(
103 "CSWAP gate requires exactly 3 wires".to_string(),
104 ));
105 }
106 let matrix = self.get_matrix(None);
107 qdev.apply_multi_qubit_gate(wires, &matrix)?;
108
109 if qdev.record_op {
110 qdev.record_operation(OpHistoryEntry {
111 name: "cswap".to_string(),
112 wires: wires.to_vec(),
113 params: None,
114 inverse: self.inverse,
115 trainable: false,
116 });
117 }
118
119 Ok(())
120 }
121
122 fn has_params(&self) -> bool {
123 false
124 }
125
126 fn trainable(&self) -> bool {
127 false
128 }
129
130 fn inverse(&self) -> bool {
131 self.inverse
132 }
133
134 fn set_inverse(&mut self, inverse: bool) {
135 self.inverse = inverse;
136 }
137}
138
139#[derive(Debug, Clone)]
141pub struct TQToffoli {
142 inverse: bool,
143 static_mode: bool,
144}
145
146impl TQToffoli {
147 pub fn new() -> Self {
148 Self {
149 inverse: false,
150 static_mode: false,
151 }
152 }
153}
154
155impl Default for TQToffoli {
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161impl TQModule for TQToffoli {
162 fn forward(&mut self, _qdev: &mut TQDevice) -> Result<()> {
163 Err(MLError::InvalidConfiguration(
164 "Use apply() instead of forward() for operators".to_string(),
165 ))
166 }
167
168 fn parameters(&self) -> Vec<TQParameter> {
169 Vec::new()
170 }
171
172 fn n_wires(&self) -> Option<usize> {
173 Some(3)
174 }
175
176 fn set_n_wires(&mut self, _n_wires: usize) {}
177
178 fn is_static_mode(&self) -> bool {
179 self.static_mode
180 }
181
182 fn static_on(&mut self) {
183 self.static_mode = true;
184 }
185
186 fn static_off(&mut self) {
187 self.static_mode = false;
188 }
189
190 fn name(&self) -> &str {
191 "Toffoli"
192 }
193}
194
195impl TQOperator for TQToffoli {
196 fn num_wires(&self) -> WiresEnum {
197 WiresEnum::Fixed(3)
198 }
199
200 fn num_params(&self) -> NParamsEnum {
201 NParamsEnum::Fixed(0)
202 }
203
204 fn get_matrix(&self, _params: Option<&[f64]>) -> Array2<CType> {
205 let mut matrix = Array2::eye(8).mapv(|x| CType::new(x, 0.0));
208 matrix[[6, 6]] = CType::new(0.0, 0.0);
210 matrix[[6, 7]] = CType::new(1.0, 0.0);
211 matrix[[7, 6]] = CType::new(1.0, 0.0);
212 matrix[[7, 7]] = CType::new(0.0, 0.0);
213 matrix
214 }
215
216 fn apply(&mut self, qdev: &mut TQDevice, wires: &[usize]) -> Result<()> {
217 self.apply_with_params(qdev, wires, None)
218 }
219
220 fn apply_with_params(
221 &mut self,
222 qdev: &mut TQDevice,
223 wires: &[usize],
224 _params: Option<&[f64]>,
225 ) -> Result<()> {
226 if wires.len() < 3 {
227 return Err(MLError::InvalidConfiguration(
228 "Toffoli gate requires exactly 3 wires".to_string(),
229 ));
230 }
231 let matrix = self.get_matrix(None);
232 qdev.apply_multi_qubit_gate(wires, &matrix)?;
233
234 if qdev.record_op {
235 qdev.record_operation(OpHistoryEntry {
236 name: "toffoli".to_string(),
237 wires: wires.to_vec(),
238 params: None,
239 inverse: self.inverse,
240 trainable: false,
241 });
242 }
243
244 Ok(())
245 }
246
247 fn has_params(&self) -> bool {
248 false
249 }
250
251 fn trainable(&self) -> bool {
252 false
253 }
254
255 fn inverse(&self) -> bool {
256 self.inverse
257 }
258
259 fn set_inverse(&mut self, inverse: bool) {
260 self.inverse = inverse;
261 }
262}
263
264#[derive(Debug, Clone)]
266pub struct TQCCZ {
267 inverse: bool,
268 static_mode: bool,
269}
270
271impl TQCCZ {
272 pub fn new() -> Self {
273 Self {
274 inverse: false,
275 static_mode: false,
276 }
277 }
278}
279
280impl Default for TQCCZ {
281 fn default() -> Self {
282 Self::new()
283 }
284}
285
286impl TQModule for TQCCZ {
287 fn forward(&mut self, _qdev: &mut TQDevice) -> Result<()> {
288 Err(MLError::InvalidConfiguration(
289 "Use apply() instead of forward() for operators".to_string(),
290 ))
291 }
292
293 fn parameters(&self) -> Vec<TQParameter> {
294 Vec::new()
295 }
296
297 fn n_wires(&self) -> Option<usize> {
298 Some(3)
299 }
300
301 fn set_n_wires(&mut self, _n_wires: usize) {}
302
303 fn is_static_mode(&self) -> bool {
304 self.static_mode
305 }
306
307 fn static_on(&mut self) {
308 self.static_mode = true;
309 }
310
311 fn static_off(&mut self) {
312 self.static_mode = false;
313 }
314
315 fn name(&self) -> &str {
316 "CCZ"
317 }
318}
319
320impl TQOperator for TQCCZ {
321 fn num_wires(&self) -> WiresEnum {
322 WiresEnum::Fixed(3)
323 }
324
325 fn num_params(&self) -> NParamsEnum {
326 NParamsEnum::Fixed(0)
327 }
328
329 fn get_matrix(&self, _params: Option<&[f64]>) -> Array2<CType> {
330 let mut matrix = Array2::eye(8).mapv(|x| CType::new(x, 0.0));
332 matrix[[7, 7]] = CType::new(-1.0, 0.0);
334 matrix
335 }
336
337 fn apply(&mut self, qdev: &mut TQDevice, wires: &[usize]) -> Result<()> {
338 self.apply_with_params(qdev, wires, None)
339 }
340
341 fn apply_with_params(
342 &mut self,
343 qdev: &mut TQDevice,
344 wires: &[usize],
345 _params: Option<&[f64]>,
346 ) -> Result<()> {
347 if wires.len() < 3 {
348 return Err(MLError::InvalidConfiguration(
349 "CCZ gate requires exactly 3 wires".to_string(),
350 ));
351 }
352 let matrix = self.get_matrix(None);
353 qdev.apply_multi_qubit_gate(wires, &matrix)?;
354
355 if qdev.record_op {
356 qdev.record_operation(OpHistoryEntry {
357 name: "ccz".to_string(),
358 wires: wires.to_vec(),
359 params: None,
360 inverse: self.inverse,
361 trainable: false,
362 });
363 }
364
365 Ok(())
366 }
367
368 fn has_params(&self) -> bool {
369 false
370 }
371
372 fn trainable(&self) -> bool {
373 false
374 }
375
376 fn inverse(&self) -> bool {
377 self.inverse
378 }
379
380 fn set_inverse(&mut self, inverse: bool) {
381 self.inverse = inverse;
382 }
383}
384
385pub type TQCCX = TQToffoli;
387pub type TQFredkin = TQCSWAP;