Line data Source code
1 : // Copyright © 2021 HQS Quantum Simulations GmbH. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4 : // in compliance with the License. You may obtain a copy of the License at
5 : //
6 : // http://www.apache.org/licenses/LICENSE-2.0
7 : //
8 : // Unless required by applicable law or agreed to in writing, software distributed under the
9 : // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
10 : // express or implied. See the License for the specific language governing permissions and
11 : // limitations under the License.
12 :
13 : use ndarray::{array, Array2};
14 : use num_complex::Complex64;
15 : use qoqo_calculator::CalculatorFloat;
16 : use std::convert::TryFrom;
17 : use std::f64::consts::PI;
18 :
19 : use crate::operations::{
20 : InvolveQubits, InvolvedQubits, Operate, OperateGate, OperateSingleQubit,
21 : OperateSingleQubitGate, Rotate, Substitute,
22 : };
23 : use crate::RoqoqoError;
24 : #[cfg(feature = "overrotate")]
25 : use rand_distr::{Distribution, Normal};
26 :
27 : /// The most general unitary operation acting on one qubit.
28 : ///
29 : /// $$ U =e^{i \phi}\begin{pmatrix}
30 : /// \alpha_r+i \alpha_i & -\beta_r+i \beta_i \\\\
31 : /// \beta_r+i \beta_i & \alpha_r-i\alpha_i
32 : /// \end{pmatrix} $$
33 : ///
34 : /// # Warning
35 : ///
36 : /// Due to the support of parameterized values it cannot be guaranteed that the unitary matrix of the gate
37 : /// is always normalized to one.
38 : ///
39 : #[derive(
40 1 : Debug,
41 45 : Clone,
42 12 : PartialEq,
43 9 : roqoqo_derive::InvolveQubits,
44 2 : roqoqo_derive::Operate,
45 9 : roqoqo_derive::Substitute,
46 78 : roqoqo_derive::OperateSingleQubit,
47 : )]
48 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
49 : pub struct SingleQubitGate {
50 : /// The qubit the unitary gate is applied to.
51 : qubit: usize,
52 : /// The real part $ \alpha_r $ of the on-diagonal elements of the single-qubit unitary.
53 : alpha_r: CalculatorFloat,
54 : /// The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary.
55 : alpha_i: CalculatorFloat,
56 : /// The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary.
57 : beta_r: CalculatorFloat,
58 : /// The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary.
59 : beta_i: CalculatorFloat,
60 : /// The global phase $ \phi $ of the single-qubit unitary.
61 : global_phase: CalculatorFloat,
62 : }
63 :
64 : #[allow(non_upper_case_globals)]
65 : const TAGS_SingleQubitGate: &[&str; 4] = &[
66 : "Operation",
67 : "GateOperation",
68 : "SingleQubitGateOperation",
69 : "SingleQubitGate",
70 : ];
71 :
72 : /// Trait for all operations acting with a unitary gate on a set of qubits.
73 : impl OperateGate for SingleQubitGate {
74 : /// Returns unitary matrix of the gate.
75 : ///
76 : /// # Returns
77 : ///
78 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
79 : /// * `Err(RoqoqoError)` - The conversion of parameters to f64 failed or matrix normalization failed.
80 118 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
81 118 : let alpha_r: f64 = f64::try_from(self.alpha_r())?;
82 117 : let alpha_i: f64 = f64::try_from(self.alpha_i())?;
83 117 : let beta_r: f64 = f64::try_from(self.beta_r())?;
84 117 : let beta_i: f64 = f64::try_from(self.beta_i())?;
85 117 : let global_phase: f64 = f64::try_from(self.global_phase())?;
86 : // before building the unitary matrix, check values of alpha and beta for the matrix to be normalized.
87 117 : if alpha_r == 0.0 && alpha_i == 0.0 && beta_r == 0.0 && beta_i == 0.0
88 116 : || (alpha_r.powf(2.0) + alpha_i.powf(2.0) + beta_r.powf(2.0) + beta_i.powf(2.0) - 1.0)
89 116 : .abs()
90 116 : > f64::EPSILON
91 : {
92 2 : let norm: f64 =
93 2 : alpha_r.powf(2.0) + alpha_i.powf(2.0) + beta_r.powf(2.0) + beta_i.powf(2.0);
94 2 : Err(RoqoqoError::UnitaryMatrixErrror {
95 2 : alpha_r,
96 2 : alpha_i,
97 2 : beta_r,
98 2 : beta_i,
99 2 : norm,
100 2 : })
101 : } else {
102 116 : let pref = Complex64::new(0.0, global_phase).exp();
103 116 : Ok(array![
104 116 : [
105 116 : pref * Complex64::new(alpha_r, alpha_i),
106 116 : pref * Complex64::new(-1.0 * beta_r, beta_i)
107 116 : ],
108 116 : [
109 116 : pref * Complex64::new(beta_r, beta_i),
110 116 : pref * Complex64::new(alpha_r, -1.0 * alpha_i)
111 116 : ]
112 116 : ])
113 : }
114 119 : }
115 : }
116 :
117 : /// Trait for unitary operations acting on exactly one qubit.
118 : impl OperateSingleQubitGate for SingleQubitGate {
119 : /// Returns the alpha_r parameter of the operation.
120 : ///
121 : /// # Returns
122 : ///
123 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
124 168 : fn alpha_r(&self) -> CalculatorFloat {
125 168 : self.alpha_r.clone()
126 168 : }
127 : /// Returns the alpha_i parameter of the operation.
128 : ///
129 : /// # Returns
130 : ///
131 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
132 166 : fn alpha_i(&self) -> CalculatorFloat {
133 166 : self.alpha_i.clone()
134 166 : }
135 : /// Returns the beta_r parameter of the operation.
136 : ///
137 : /// # Returns
138 : ///
139 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
140 168 : fn beta_r(&self) -> CalculatorFloat {
141 168 : self.beta_r.clone()
142 168 : }
143 : /// Returns the beta_i parameter of the operation.
144 : ///
145 : /// # Returns
146 : ///
147 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
148 167 : fn beta_i(&self) -> CalculatorFloat {
149 167 : self.beta_i.clone()
150 167 : }
151 : /// Returns global_phase parameter of the operation.
152 : ///
153 : /// # Returns
154 : ///
155 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
156 164 : fn global_phase(&self) -> CalculatorFloat {
157 164 : self.global_phase.clone()
158 164 : }
159 : }
160 :
161 : /// The ZPower gate $e^{-i \frac{\theta}{2} \sigma^z}$.
162 : ///
163 : /// $$
164 : /// U = \begin{pmatrix}
165 : /// \cos(\frac{\theta}{2}) & 0\\\\
166 : /// 0 & \cos(\frac{\theta}{2})
167 : /// \end{pmatrix}
168 : /// + \begin{pmatrix}
169 : /// -i \sin(\frac{\theta}{2}) & 0\\\\
170 : /// 0 & i \sin(\frac{\theta}{2})
171 : /// \end{pmatrix}
172 : /// $$
173 : ///
174 : #[derive(
175 1 : Debug,
176 180 : Clone,
177 55 : PartialEq,
178 9 : roqoqo_derive::InvolveQubits,
179 267 : roqoqo_derive::Operate,
180 21 : roqoqo_derive::Substitute,
181 70 : roqoqo_derive::OperateSingleQubit,
182 14 : roqoqo_derive::Rotate,
183 : )]
184 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
185 : pub struct RotateZ {
186 : /// The qubit the unitary gate is applied to.
187 : qubit: usize,
188 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2^* 2 \pi$.
189 : theta: CalculatorFloat,
190 : }
191 :
192 : #[allow(non_upper_case_globals)]
193 : const TAGS_RotateZ: &[&str; 5] = &[
194 : "Operation",
195 : "GateOperation",
196 : "SingleQubitGateOperation",
197 : "Rotation",
198 : "RotateZ",
199 : ];
200 :
201 : /// Trait for all operations acting with a unitary gate on a set of qubits.
202 : impl OperateGate for RotateZ {
203 : /// Returns unitary matrix of the gate.
204 : ///
205 : /// # Returns
206 : ///
207 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
208 : /// * `Err(RoqoqoError)` - The conversion of theta to f64 failed.
209 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
210 2 : let c: f64 = (f64::try_from(self.theta.clone())? / 2.0).cos();
211 2 : let s: f64 = (f64::try_from(self.theta.clone())? / 2.0).sin();
212 2 : Ok(array![
213 2 : [Complex64::new(c, -1.0 * s), Complex64::new(0.0, 0.0)],
214 2 : [Complex64::new(0.0, 0.0), Complex64::new(c, s)]
215 2 : ])
216 2 : }
217 : }
218 :
219 : /// Trait for unitary operations acting on exactly one qubit.
220 : impl OperateSingleQubitGate for RotateZ {
221 : /// Returns the alpha_r parameter of the operation.
222 : ///
223 : /// # Returns
224 : ///
225 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
226 43 : fn alpha_r(&self) -> CalculatorFloat {
227 43 : (self.theta.clone() / 2.0).cos()
228 43 : }
229 :
230 : /// Returns the alpha_i parameter of the operation.
231 : ///
232 : /// # Returns
233 : ///
234 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
235 43 : fn alpha_i(&self) -> CalculatorFloat {
236 43 : (self.theta.clone() / 2.0).sin() * (-1.0)
237 43 : }
238 :
239 : /// Returns the beta_r parameter of the operation.
240 : ///
241 : /// # Returns
242 : ///
243 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
244 40 : fn beta_r(&self) -> CalculatorFloat {
245 40 : CalculatorFloat::from(0.0)
246 40 : }
247 :
248 : /// Returns the beta_i parameter of the operation.
249 : ///
250 : /// # Returns
251 : ///
252 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
253 40 : fn beta_i(&self) -> CalculatorFloat {
254 40 : CalculatorFloat::from(0.0)
255 40 : }
256 :
257 : /// Returns global_phase parameter of the operation.
258 : ///
259 : /// # Returns
260 : ///
261 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
262 39 : fn global_phase(&self) -> CalculatorFloat {
263 39 : CalculatorFloat::from(0.0)
264 39 : }
265 : }
266 :
267 : /// The XPower gate $e^{-i \frac{\theta}{2} \sigma^x}$.
268 : ///
269 : /// $$
270 : /// U = \begin{pmatrix}
271 : /// \cos(\frac{\theta}{2}) & 0\\\\
272 : /// 0 & \cos(\frac{\theta}{2})
273 : /// \end{pmatrix}
274 : /// + \begin{pmatrix}
275 : /// 0 & -i \sin(\frac{\theta}{2}) \\\\
276 : /// -i \sin(\frac{\theta}{2}) & 0
277 : /// \end{pmatrix}
278 : /// $$
279 : ///
280 : #[derive(
281 5 : Debug,
282 74 : Clone,
283 41 : PartialEq,
284 10 : roqoqo_derive::InvolveQubits,
285 164 : roqoqo_derive::Operate,
286 19 : roqoqo_derive::Substitute,
287 23 : roqoqo_derive::OperateSingleQubit,
288 26 : roqoqo_derive::Rotate,
289 : )]
290 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
291 : pub struct RotateX {
292 : /// The qubit the unitary gate is applied to.
293 : qubit: usize,
294 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2^* 2 \pi$.
295 : theta: CalculatorFloat,
296 : }
297 : #[allow(non_upper_case_globals)]
298 : const TAGS_RotateX: &[&str; 5] = &[
299 : "Operation",
300 : "GateOperation",
301 : "SingleQubitGateOperation",
302 : "Rotation",
303 : "RotateX",
304 : ];
305 :
306 : /// Trait for all operations acting with a unitary gate on a set of qubits.
307 : impl OperateGate for RotateX {
308 : /// Returns unitary matrix of the gate.
309 : ///
310 : /// # Returns
311 : ///
312 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
313 : /// * `Err(RoqoqoError)` - The conversion of theta to f64 failed.
314 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
315 2 : let c: f64 = (f64::try_from(self.theta.clone())? / 2.0).cos();
316 2 : let s: f64 = (f64::try_from(self.theta.clone())? / 2.0).sin();
317 2 : Ok(array![
318 2 : [Complex64::new(c, 0.0), Complex64::new(0.0, -1.0 * s)],
319 2 : [Complex64::new(0.0, -1.0 * s), Complex64::new(c, 0.0)]
320 2 : ])
321 2 : }
322 : }
323 :
324 : /// Trait for unitary operations acting on exactly one qubit.
325 : impl OperateSingleQubitGate for RotateX {
326 : /// Returns the alpha_r parameter of the operation.
327 : ///
328 : /// # Returns
329 : ///
330 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
331 29 : fn alpha_r(&self) -> CalculatorFloat {
332 29 : (self.theta.clone() / 2.0).cos()
333 29 : }
334 : /// Returns the alpha_i parameter of the operation.
335 : ///
336 : /// # Returns
337 : ///
338 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
339 26 : fn alpha_i(&self) -> CalculatorFloat {
340 26 : CalculatorFloat::from(0.0)
341 26 : }
342 : /// Returns the beta_r parameter of the operation.
343 : ///
344 : /// # Returns
345 : ///
346 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
347 26 : fn beta_r(&self) -> CalculatorFloat {
348 26 : CalculatorFloat::from(0.0)
349 26 : }
350 : /// Returns the beta_i parameter of the operation.
351 : ///
352 : /// # Returns
353 : ///
354 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
355 29 : fn beta_i(&self) -> CalculatorFloat {
356 29 : (self.theta.clone() / 2.0).sin() * (-1.0)
357 29 : }
358 : /// Returns global_phase parameter of the operation.
359 : ///
360 : /// # Returns
361 : ///
362 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
363 26 : fn global_phase(&self) -> CalculatorFloat {
364 26 : CalculatorFloat::from(0.0)
365 26 : }
366 : }
367 :
368 : /// The YPower gate $e^{-i \frac{\theta}{2} \sigma^y}$.
369 : ///
370 : /// $$
371 : /// U = \begin{pmatrix}
372 : /// \cos(\frac{\theta}{2}) & 0\\\\
373 : /// 0 & \cos(\frac{\theta}{2})
374 : /// \end{pmatrix}
375 : /// + \begin{pmatrix}
376 : /// 0 & - \sin(\frac{\theta}{2})\\\\
377 : /// \sin(\frac{\theta}{2}) & 0
378 : /// \end{pmatrix}
379 : /// $$
380 : ///
381 : #[derive(
382 1 : Debug,
383 33 : Clone,
384 18 : PartialEq,
385 9 : roqoqo_derive::InvolveQubits,
386 64 : roqoqo_derive::Operate,
387 9 : roqoqo_derive::Substitute,
388 19 : roqoqo_derive::OperateSingleQubit,
389 14 : roqoqo_derive::Rotate,
390 : )]
391 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
392 : pub struct RotateY {
393 : /// The qubit the unitary gate is applied to.
394 : qubit: usize,
395 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2^* 2 \pi$.
396 : theta: CalculatorFloat,
397 : }
398 : #[allow(non_upper_case_globals)]
399 : const TAGS_RotateY: &[&str; 5] = &[
400 : "Operation",
401 : "GateOperation",
402 : "SingleQubitGateOperation",
403 : "Rotation",
404 : "RotateY",
405 : ];
406 :
407 : /// Trait for all operations acting with a unitary gate on a set of qubits.
408 : impl OperateGate for RotateY {
409 : /// Returns unitary matrix of the gate.
410 : ///
411 : /// # Returns
412 : ///
413 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
414 : /// * `Err(RoqoqoError)` - The conversion of theta to f64 failed.
415 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
416 2 : let c: f64 = (f64::try_from(self.theta.clone())? / 2.0).cos();
417 2 : let s: f64 = (f64::try_from(self.theta.clone())? / 2.0).sin();
418 2 : Ok(array![
419 2 : [Complex64::new(c, 0.0), Complex64::new(-1.0 * s, 0.0)],
420 2 : [Complex64::new(s, 0.0), Complex64::new(c, 0.0)]
421 2 : ])
422 2 : }
423 : }
424 :
425 : /// Trait for unitary operations acting on exactly one qubit.
426 : impl OperateSingleQubitGate for RotateY {
427 : /// Returns the alpha_r parameter of the operation.
428 : ///
429 : /// # Returns
430 : ///
431 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
432 14 : fn alpha_r(&self) -> CalculatorFloat {
433 14 : (self.theta.clone() / 2.0).cos()
434 14 : }
435 : /// Returns the alpha_i parameter of the operation.
436 : ///
437 : /// # Returns
438 : ///
439 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
440 11 : fn alpha_i(&self) -> CalculatorFloat {
441 11 : CalculatorFloat::from(0.0)
442 11 : }
443 : /// Returns the beta_r parameter of the operation.
444 : ///
445 : /// # Returns
446 : ///
447 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
448 14 : fn beta_r(&self) -> CalculatorFloat {
449 14 : (self.theta.clone() / 2.0).sin()
450 14 : }
451 : /// Returns the beta_i parameter of the operation.
452 : ///
453 : /// # Returns
454 : ///
455 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
456 11 : fn beta_i(&self) -> CalculatorFloat {
457 11 : CalculatorFloat::from(0.0)
458 11 : }
459 : /// Returns global_phase parameter of the operation.
460 : ///
461 : /// # Returns
462 : ///
463 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
464 11 : fn global_phase(&self) -> CalculatorFloat {
465 11 : CalculatorFloat::from(0.0)
466 11 : }
467 : }
468 :
469 : /// The Pauli X gate.
470 : ///
471 : /// $$
472 : /// U = \begin{pmatrix}
473 : /// 0 & 1\\\\
474 : /// 1 & 0
475 : /// \end{pmatrix}
476 : /// $$
477 : ///
478 : #[derive(
479 2 : Debug,
480 24 : Clone,
481 22 : PartialEq,
482 5 : roqoqo_derive::InvolveQubits,
483 53 : roqoqo_derive::Operate,
484 9 : roqoqo_derive::Substitute,
485 11 : roqoqo_derive::OperateSingleQubit,
486 : )]
487 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
488 : pub struct PauliX {
489 : /// The qubit the unitary gate is applied to.
490 : qubit: usize,
491 : }
492 :
493 : #[allow(non_upper_case_globals)]
494 : const TAGS_PauliX: &[&str; 4] = &[
495 : "Operation",
496 : "GateOperation",
497 : "SingleQubitGateOperation",
498 : "PauliX",
499 : ];
500 :
501 : /// Trait for all operations acting with a unitary gate on a set of qubits.
502 : impl OperateGate for PauliX {
503 : /// Returns unitary matrix of the gate.
504 : ///
505 : /// # Returns
506 : ///
507 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
508 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
509 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
510 2 : Ok(array![
511 2 : [Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)],
512 2 : [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]
513 2 : ])
514 2 : }
515 : }
516 :
517 : /// Trait for unitary operations acting on exactly one qubit.
518 : impl OperateSingleQubitGate for PauliX {
519 : /// Returns the alpha_r parameter of the operation.
520 : ///
521 : /// # Returns
522 : ///
523 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
524 5 : fn alpha_r(&self) -> CalculatorFloat {
525 5 : CalculatorFloat::from(0.0)
526 5 : }
527 : /// Returns the alpha_i parameter of the operation.
528 : ///
529 : /// # Returns
530 : ///
531 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
532 5 : fn alpha_i(&self) -> CalculatorFloat {
533 5 : CalculatorFloat::from(0.0)
534 5 : }
535 : /// Returns the beta_r parameter of the operation.
536 : ///
537 : /// # Returns
538 : ///
539 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
540 5 : fn beta_r(&self) -> CalculatorFloat {
541 5 : CalculatorFloat::from(0.0)
542 5 : }
543 : /// Returns the beta_i parameter of the operation.
544 : ///
545 : /// # Returns
546 : ///
547 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
548 5 : fn beta_i(&self) -> CalculatorFloat {
549 5 : CalculatorFloat::from(-1.0)
550 5 : }
551 : /// Returns global_phase parameter of the operation.
552 : ///
553 : /// # Returns
554 : ///
555 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
556 5 : fn global_phase(&self) -> CalculatorFloat {
557 5 : CalculatorFloat::from((PI) / 2.0)
558 5 : }
559 : }
560 :
561 : /// The Pauli Y gate.
562 : ///
563 : /// $$
564 : /// U = \begin{pmatrix}
565 : /// 0 & -i\\\\
566 : /// i & 0
567 : /// \end{pmatrix}
568 : /// $$
569 : ///
570 : #[derive(
571 1 : Debug,
572 8 : Clone,
573 8 : PartialEq,
574 3 : roqoqo_derive::InvolveQubits,
575 29 : roqoqo_derive::Operate,
576 3 : roqoqo_derive::Substitute,
577 11 : roqoqo_derive::OperateSingleQubit,
578 : )]
579 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
580 : pub struct PauliY {
581 : /// The qubit the unitary gate is applied to.
582 : qubit: usize,
583 : }
584 :
585 : #[allow(non_upper_case_globals)]
586 : const TAGS_PauliY: &[&str; 4] = &[
587 : "Operation",
588 : "GateOperation",
589 : "SingleQubitGateOperation",
590 : "PauliY",
591 : ];
592 :
593 : /// Trait for all operations acting with a unitary gate on a set of qubits.
594 : impl OperateGate for PauliY {
595 : /// Returns unitary matrix of the gate.
596 : ///
597 : /// # Returns
598 : ///
599 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
600 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
601 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
602 2 : Ok(array![
603 2 : [Complex64::new(0.0, 0.0), Complex64::new(0.0, -1.0)],
604 2 : [Complex64::new(0.0, 1.0), Complex64::new(0.0, 0.0)]
605 2 : ])
606 2 : }
607 : }
608 :
609 : /// Trait for unitary operations acting on exactly one qubit.
610 : impl OperateSingleQubitGate for PauliY {
611 : /// Returns the alpha_r parameter of the operation.
612 : ///
613 : /// # Returns
614 : ///
615 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
616 5 : fn alpha_r(&self) -> CalculatorFloat {
617 5 : CalculatorFloat::from(0.0)
618 5 : }
619 : /// Returns the alpha_i parameter of the operation.
620 : ///
621 : /// # Returns
622 : ///
623 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
624 5 : fn alpha_i(&self) -> CalculatorFloat {
625 5 : CalculatorFloat::from(0.0)
626 5 : }
627 : /// Returns the beta_r parameter of the operation.
628 : ///
629 : /// # Returns
630 : ///
631 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
632 5 : fn beta_r(&self) -> CalculatorFloat {
633 5 : CalculatorFloat::from(1.0)
634 5 : }
635 : /// Returns the beta_i parameter of the operation.
636 : ///
637 : /// # Returns
638 : ///
639 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
640 5 : fn beta_i(&self) -> CalculatorFloat {
641 5 : CalculatorFloat::from(0.0)
642 5 : }
643 : /// Returns global_phase parameter of the operation.
644 : ///
645 : /// # Returns
646 : ///
647 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
648 5 : fn global_phase(&self) -> CalculatorFloat {
649 5 : CalculatorFloat::from(PI / 2.0)
650 5 : }
651 : }
652 :
653 : /// The Pauli Z gate.
654 : ///
655 : /// $$
656 : /// U = \begin{pmatrix}
657 : /// 1 & 0 \\\\
658 : /// 0 & -1
659 : /// \end{pmatrix}
660 : /// $$
661 : ///
662 : #[derive(
663 4 : Debug,
664 21 : Clone,
665 18 : PartialEq,
666 3 : roqoqo_derive::InvolveQubits,
667 34 : roqoqo_derive::Operate,
668 3 : roqoqo_derive::Substitute,
669 8 : roqoqo_derive::OperateSingleQubit,
670 : )]
671 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
672 : pub struct PauliZ {
673 : /// The qubit the unitary gate is applied to.
674 : qubit: usize,
675 : }
676 :
677 : #[allow(non_upper_case_globals)]
678 : const TAGS_PauliZ: &[&str; 4] = &[
679 : "Operation",
680 : "GateOperation",
681 : "SingleQubitGateOperation",
682 : "PauliZ",
683 : ];
684 :
685 : /// Trait for all operations acting with a unitary gate on a set of qubits.
686 : impl OperateGate for PauliZ {
687 : /// Returns unitary matrix of the gate.
688 : ///
689 : /// # Returns
690 : ///
691 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
692 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
693 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
694 2 : Ok(array![
695 2 : [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
696 2 : [Complex64::new(0.0, 0.0), Complex64::new(-1.0, 0.0)]
697 2 : ])
698 2 : }
699 : }
700 :
701 : /// Trait for unitary operations acting on exactly one qubit.
702 : impl OperateSingleQubitGate for PauliZ {
703 : /// Returns the alpha_r parameter of the operation.
704 : ///
705 : /// # Returns
706 : ///
707 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
708 5 : fn alpha_r(&self) -> CalculatorFloat {
709 5 : CalculatorFloat::from(0.0)
710 5 : }
711 : /// Returns the alpha_i parameter of the operation.
712 : ///
713 : /// # Returns
714 : ///
715 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
716 5 : fn alpha_i(&self) -> CalculatorFloat {
717 5 : CalculatorFloat::from(-1.0)
718 5 : }
719 : /// Returns the beta_r parameter of the operation.
720 : ///
721 : /// # Returns
722 : ///
723 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
724 5 : fn beta_r(&self) -> CalculatorFloat {
725 5 : CalculatorFloat::from(0.0)
726 5 : }
727 : /// Returns the beta_i parameter of the operation.
728 : ///
729 : /// # Returns
730 : ///
731 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
732 5 : fn beta_i(&self) -> CalculatorFloat {
733 5 : CalculatorFloat::from(0.0)
734 5 : }
735 : /// Returns global_phase parameter of the operation.
736 : ///
737 : /// # Returns
738 : ///
739 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
740 5 : fn global_phase(&self) -> CalculatorFloat {
741 5 : CalculatorFloat::from(PI / 2.0)
742 5 : }
743 : }
744 :
745 : /// The square root of the XPower gate: $e^{-i \frac{\pi}{4} \sigma^x}$.
746 : ///
747 : /// $$
748 : /// U = \frac{1}{\sqrt(2)}\begin{pmatrix}
749 : /// 1 & -i \\\\
750 : /// -i & 1
751 : /// \end{pmatrix}
752 : /// $$
753 : ///
754 : #[derive(
755 1 : Debug,
756 8 : Clone,
757 8 : PartialEq,
758 3 : roqoqo_derive::InvolveQubits,
759 25 : roqoqo_derive::Operate,
760 3 : roqoqo_derive::Substitute,
761 3 : roqoqo_derive::OperateSingleQubit,
762 : )]
763 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
764 : pub struct SqrtPauliX {
765 : /// The qubit the unitary gate is applied to.
766 : qubit: usize,
767 : }
768 :
769 : #[allow(non_upper_case_globals)]
770 : const TAGS_SqrtPauliX: &[&str; 4] = &[
771 : "Operation",
772 : "GateOperation",
773 : "SingleQubitGateOperation",
774 : "SqrtPauliX",
775 : ];
776 :
777 : /// Trait for all operations acting with a unitary gate on a set of qubits.
778 : impl OperateGate for SqrtPauliX {
779 : /// Returns unitary matrix of the gate.
780 : ///
781 : /// # Returns
782 : ///
783 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
784 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
785 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
786 2 : let theta: f64 = PI / 2.0;
787 2 : let c: f64 = (theta / 2.0).cos();
788 2 : let s: f64 = (theta / 2.0).sin();
789 2 : Ok(array![
790 2 : [Complex64::new(c, 0.0), Complex64::new(0.0, -1.0 * s)],
791 2 : [Complex64::new(0.0, -1.0 * s), Complex64::new(c, 0.0)]
792 2 : ])
793 2 : }
794 : }
795 :
796 : /// Trait for unitary operations acting on exactly one qubit.
797 : impl OperateSingleQubitGate for SqrtPauliX {
798 : /// Returns the alpha_r parameter of the operation.
799 : ///
800 : /// # Returns
801 : ///
802 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
803 2 : fn alpha_r(&self) -> CalculatorFloat {
804 2 : CalculatorFloat::from((PI / 4.0).cos())
805 2 : }
806 : /// Returns the alpha_i parameter of the operation.
807 : ///
808 : /// # Returns
809 : ///
810 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
811 2 : fn alpha_i(&self) -> CalculatorFloat {
812 2 : CalculatorFloat::from(0.0)
813 2 : }
814 : /// Returns the beta_r parameter of the operation.
815 : ///
816 : /// # Returns
817 : ///
818 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
819 2 : fn beta_r(&self) -> CalculatorFloat {
820 2 : CalculatorFloat::from(0.0)
821 2 : }
822 : /// Returns the beta_i parameter of the operation.
823 : ///
824 : /// # Returns
825 : ///
826 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
827 2 : fn beta_i(&self) -> CalculatorFloat {
828 2 : CalculatorFloat::from((PI / 4.0).sin() * (-1.0))
829 2 : }
830 : /// Returns global_phase parameter of the operation.
831 : ///
832 : /// # Returns
833 : ///
834 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
835 2 : fn global_phase(&self) -> CalculatorFloat {
836 2 : CalculatorFloat::from(0.0)
837 2 : }
838 : }
839 :
840 : /// The inverse square root of the XPower gate: $e^{i \frac{\pi}{2} \sigma^x}$.
841 : ///
842 : /// $$
843 : /// U = \frac{1}{\sqrt{2}} \begin{pmatrix}
844 : /// 1 & i \\\\
845 : /// i & 1
846 : /// \end{pmatrix}
847 : /// $$
848 : ///
849 : #[derive(
850 1 : Debug,
851 8 : Clone,
852 8 : PartialEq,
853 3 : roqoqo_derive::InvolveQubits,
854 25 : roqoqo_derive::Operate,
855 3 : roqoqo_derive::Substitute,
856 3 : roqoqo_derive::OperateSingleQubit,
857 : )]
858 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
859 : pub struct InvSqrtPauliX {
860 : /// The qubit the unitary gate is applied to.
861 : qubit: usize,
862 : }
863 :
864 : #[allow(non_upper_case_globals)]
865 : const TAGS_InvSqrtPauliX: &[&str; 4] = &[
866 : "Operation",
867 : "GateOperation",
868 : "SingleQubitGateOperation",
869 : "InvSqrtPauliX",
870 : ];
871 :
872 : /// Trait for all operations acting with a unitary gate on a set of qubits.
873 : impl OperateGate for InvSqrtPauliX {
874 : /// Returns unitary matrix of the gate.
875 : ///
876 : /// # Returns
877 : ///
878 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
879 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
880 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
881 2 : let theta: f64 = PI / 2.0;
882 2 : let c: f64 = (theta / 2.0).cos();
883 2 : let s: f64 = (theta / 2.0).sin();
884 2 : Ok(array![
885 2 : [Complex64::new(c, 0.0), Complex64::new(0.0, 1.0 * s)],
886 2 : [Complex64::new(0.0, 1.0 * s), Complex64::new(c, 0.0)]
887 2 : ])
888 2 : }
889 : }
890 :
891 : /// Trait for unitary operations acting on exactly one qubit.
892 : impl OperateSingleQubitGate for InvSqrtPauliX {
893 : /// Returns the alpha_r parameter of the operation.
894 : ///
895 : /// # Returns
896 : ///
897 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
898 2 : fn alpha_r(&self) -> CalculatorFloat {
899 2 : CalculatorFloat::from((PI / 4.0).cos())
900 2 : }
901 : /// Returns the alpha_i parameter of the operation.
902 : ///
903 : /// # Returns
904 : ///
905 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
906 2 : fn alpha_i(&self) -> CalculatorFloat {
907 2 : CalculatorFloat::from(0.0)
908 2 : }
909 : /// Returns the beta_r parameter of the operation.
910 : ///
911 : /// # Returns
912 : ///
913 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
914 2 : fn beta_r(&self) -> CalculatorFloat {
915 2 : CalculatorFloat::from(0.0)
916 2 : }
917 : /// Returns the beta_i parameter of the operation.
918 : ///
919 : /// # Returns
920 : ///
921 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
922 2 : fn beta_i(&self) -> CalculatorFloat {
923 2 : CalculatorFloat::from((PI / 4.0).sin())
924 2 : }
925 : /// Returns global_phase parameter of the operation.
926 : ///
927 : /// # Returns
928 : ///
929 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
930 2 : fn global_phase(&self) -> CalculatorFloat {
931 2 : CalculatorFloat::from(0.0)
932 2 : }
933 : }
934 :
935 : /// The Hadamard gate.
936 : ///
937 : /// $$
938 : /// U = \frac{1}{\sqrt{2}} \begin{pmatrix}
939 : /// 1 & 1\\\\
940 : /// 1 & -1
941 : /// \end{pmatrix}
942 : /// $$
943 : ///
944 : #[derive(
945 1 : Debug,
946 8 : Clone,
947 18 : PartialEq,
948 3 : roqoqo_derive::InvolveQubits,
949 46 : roqoqo_derive::Operate,
950 3 : roqoqo_derive::Substitute,
951 3 : roqoqo_derive::OperateSingleQubit,
952 : )]
953 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
954 : pub struct Hadamard {
955 : /// The qubit the unitary gate is applied to.
956 : qubit: usize,
957 : }
958 :
959 : #[allow(non_upper_case_globals)]
960 : const TAGS_Hadamard: &[&str; 4] = &[
961 : "Operation",
962 : "GateOperation",
963 : "SingleQubitGateOperation",
964 : "Hadamard",
965 : ];
966 :
967 : /// Trait for all operations acting with a unitary gate on a set of qubits.
968 : impl OperateGate for Hadamard {
969 : /// Returns unitary matrix of the gate.
970 : ///
971 : /// # Returns
972 : ///
973 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
974 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
975 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
976 2 : let f: f64 = 1.0 / ((2.0_f64).sqrt());
977 2 : Ok(array![
978 2 : [Complex64::new(f, 0.0), Complex64::new(f, 0.0)],
979 2 : [Complex64::new(f, 0.0), Complex64::new(-1.0 * f, 0.0)]
980 2 : ])
981 2 : }
982 : }
983 :
984 : /// Trait for unitary operations acting on exactly one qubit.
985 : impl OperateSingleQubitGate for Hadamard {
986 : /// Returns the alpha_r parameter of the operation.
987 : ///
988 : /// # Returns
989 : ///
990 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
991 3 : fn alpha_r(&self) -> CalculatorFloat {
992 3 : CalculatorFloat::from(0.0)
993 3 : }
994 : /// Returns the alpha_i parameter of the operation.
995 : ///
996 : /// # Returns
997 : ///
998 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
999 3 : fn alpha_i(&self) -> CalculatorFloat {
1000 3 : CalculatorFloat::from(-1.0 / ((2.0_f64).sqrt()))
1001 3 : }
1002 : /// Returns the beta_r parameter of the operation.
1003 : ///
1004 : /// # Returns
1005 : ///
1006 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1007 3 : fn beta_r(&self) -> CalculatorFloat {
1008 3 : CalculatorFloat::from(0.0)
1009 3 : }
1010 : /// Returns the beta_i parameter of the operation.
1011 : ///
1012 : /// # Returns
1013 : ///
1014 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1015 3 : fn beta_i(&self) -> CalculatorFloat {
1016 3 : CalculatorFloat::from(-1.0 / ((2.0_f64).sqrt()))
1017 3 : }
1018 : /// Returns global_phase parameter of the operation.
1019 : ///
1020 : /// # Returns
1021 : ///
1022 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1023 2 : fn global_phase(&self) -> CalculatorFloat {
1024 2 : CalculatorFloat::from(PI / 2.0)
1025 2 : }
1026 : }
1027 :
1028 : /// The S gate.
1029 : ///
1030 : /// $$
1031 : /// U = \frac{1}{\sqrt{2}} \begin{pmatrix}
1032 : /// 1 & 0\\\\
1033 : /// 0 & i
1034 : /// \end{pmatrix}
1035 : /// $$
1036 : ///
1037 : #[derive(
1038 1 : Debug,
1039 8 : Clone,
1040 8 : PartialEq,
1041 3 : roqoqo_derive::InvolveQubits,
1042 25 : roqoqo_derive::Operate,
1043 3 : roqoqo_derive::Substitute,
1044 3 : roqoqo_derive::OperateSingleQubit,
1045 : )]
1046 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1047 : pub struct SGate {
1048 : /// The qubit the unitary gate is applied to.
1049 : qubit: usize,
1050 : }
1051 :
1052 : #[allow(non_upper_case_globals)]
1053 : const TAGS_SGate: &[&str; 4] = &[
1054 : "Operation",
1055 : "GateOperation",
1056 : "SingleQubitGateOperation",
1057 : "SGate",
1058 : ];
1059 :
1060 : /// Trait for all operations acting with a unitary gate on a set of qubits.
1061 : impl OperateGate for SGate {
1062 : /// Returns unitary matrix of the gate.
1063 : ///
1064 : /// # Returns
1065 : ///
1066 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
1067 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
1068 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
1069 2 : Ok(array![
1070 2 : [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
1071 2 : [Complex64::new(0.0, 0.0), Complex64::new(0.0, 1.0)]
1072 2 : ])
1073 2 : }
1074 : }
1075 :
1076 : /// Trait for unitary operations acting on exactly one qubit.
1077 : impl OperateSingleQubitGate for SGate {
1078 : /// Returns the alpha_r parameter of the operation.
1079 : ///
1080 : /// # Returns
1081 : ///
1082 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
1083 2 : fn alpha_r(&self) -> CalculatorFloat {
1084 2 : CalculatorFloat::from(1.0 / ((2.0_f64).sqrt()))
1085 2 : }
1086 : /// Returns the alpha_i parameter of the operation.
1087 : ///
1088 : /// # Returns
1089 : ///
1090 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
1091 2 : fn alpha_i(&self) -> CalculatorFloat {
1092 2 : CalculatorFloat::from(-1.0 / ((2.0_f64).sqrt()))
1093 2 : }
1094 : /// Returns the beta_r parameter of the operation.
1095 : ///
1096 : /// # Returns
1097 : ///
1098 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1099 2 : fn beta_r(&self) -> CalculatorFloat {
1100 2 : CalculatorFloat::from(0.0)
1101 2 : }
1102 : /// Returns the beta_i parameter of the operation.
1103 : ///
1104 : /// # Returns
1105 : ///
1106 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1107 2 : fn beta_i(&self) -> CalculatorFloat {
1108 2 : CalculatorFloat::from(0.0)
1109 2 : }
1110 : /// Returns global_phase parameter of the operation.
1111 : ///
1112 : /// # Returns
1113 : ///
1114 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1115 2 : fn global_phase(&self) -> CalculatorFloat {
1116 2 : CalculatorFloat::from(PI / 4.0)
1117 2 : }
1118 : }
1119 :
1120 : /// The T gate.
1121 : ///
1122 : /// $$
1123 : /// U = \frac{1}{\sqrt{2}} \begin{pmatrix}
1124 : /// 1 & 0\\\\
1125 : /// 0 & e^{i \frac{\pi}{4}}
1126 : /// \end{pmatrix}
1127 : /// $$
1128 : ///
1129 : #[derive(
1130 1 : Debug,
1131 8 : Clone,
1132 8 : PartialEq,
1133 3 : roqoqo_derive::InvolveQubits,
1134 25 : roqoqo_derive::Operate,
1135 3 : roqoqo_derive::Substitute,
1136 3 : roqoqo_derive::OperateSingleQubit,
1137 : )]
1138 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1139 : pub struct TGate {
1140 : /// The qubit the unitary gate is applied to.
1141 : qubit: usize,
1142 : }
1143 :
1144 : #[allow(non_upper_case_globals)]
1145 : const TAGS_TGate: &[&str; 4] = &[
1146 : "Operation",
1147 : "GateOperation",
1148 : "SingleQubitGateOperation",
1149 : "TGate",
1150 : ];
1151 :
1152 : /// Trait for all operations acting with a unitary gate on a set of qubits.
1153 : impl OperateGate for TGate {
1154 : /// Returns unitary matrix of the gate.
1155 : ///
1156 : /// # Returns
1157 : ///
1158 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
1159 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
1160 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
1161 2 : Ok(array![
1162 2 : [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
1163 2 : [
1164 2 : Complex64::new(0.0, 0.0),
1165 2 : Complex64::new((PI / 4.0).cos(), (PI / 4.0).sin())
1166 2 : ] //exp(i*pi/4) = cos(pi/4) + i*sin(pi/4)
1167 2 : ])
1168 2 : }
1169 : }
1170 :
1171 : /// Trait for unitary operations acting on exactly one qubit.
1172 : impl OperateSingleQubitGate for TGate {
1173 : /// Returns the alpha_r parameter of the operation.
1174 : ///
1175 : /// # Returns
1176 : ///
1177 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
1178 2 : fn alpha_r(&self) -> CalculatorFloat {
1179 2 : CalculatorFloat::from((PI / 8.0).cos())
1180 2 : }
1181 : /// Returns the alpha_i parameter of the operation.
1182 : ///
1183 : /// # Returns
1184 : ///
1185 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
1186 2 : fn alpha_i(&self) -> CalculatorFloat {
1187 2 : CalculatorFloat::from((-1.0) * (PI / 8.0).sin())
1188 2 : }
1189 : /// Returns the beta_r parameter of the operation.
1190 : ///
1191 : /// # Returns
1192 : ///
1193 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1194 2 : fn beta_r(&self) -> CalculatorFloat {
1195 2 : CalculatorFloat::from(0.0)
1196 2 : }
1197 : /// Returns the beta_i parameter of the operation.
1198 : ///
1199 : /// # Returns
1200 : ///
1201 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1202 2 : fn beta_i(&self) -> CalculatorFloat {
1203 2 : CalculatorFloat::from(0.0)
1204 2 : }
1205 : /// Returns global_phase parameter of the operation.
1206 : ///
1207 : /// # Returns
1208 : ///
1209 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1210 2 : fn global_phase(&self) -> CalculatorFloat {
1211 2 : CalculatorFloat::from(PI / 8.0)
1212 2 : }
1213 : }
1214 :
1215 : /// The phase shift gate applied on state |1>.
1216 : ///
1217 : /// Rotation around Z-axis by an arbitrary angle $\theta$ (AC Stark shift of the state |1>).
1218 : ///
1219 : /// $$
1220 : /// U = \begin{pmatrix}
1221 : /// 1 & 0\\\\
1222 : /// 0 & e^{i \theta}
1223 : /// \end{pmatrix}
1224 : /// $$
1225 : ///
1226 : #[derive(
1227 1 : Debug,
1228 9 : Clone,
1229 10 : PartialEq,
1230 3 : roqoqo_derive::InvolveQubits,
1231 35 : roqoqo_derive::Operate,
1232 5 : roqoqo_derive::Substitute,
1233 3 : roqoqo_derive::OperateSingleQubit,
1234 19 : roqoqo_derive::Rotate,
1235 : )]
1236 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1237 : pub struct PhaseShiftState1 {
1238 : /// The qubit the unitary gate is applied to.
1239 : qubit: usize,
1240 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2 \pi$.
1241 : theta: CalculatorFloat,
1242 : }
1243 :
1244 : #[allow(non_upper_case_globals)]
1245 : const TAGS_PhaseShiftState1: &[&str; 5] = &[
1246 : "Operation",
1247 : "GateOperation",
1248 : "SingleQubitGateOperation",
1249 : "Rotation",
1250 : "PhaseShiftState1",
1251 : ];
1252 :
1253 : /// Trait for all operations acting with a unitary gate on a set of qubits.
1254 : impl OperateGate for PhaseShiftState1 {
1255 : /// Returns unitary matrix of the gate.
1256 : ///
1257 : /// # Returns
1258 : ///
1259 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
1260 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
1261 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
1262 2 : let theta: f64 = f64::try_from(self.theta().clone())?;
1263 2 : Ok(array![
1264 2 : [Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
1265 2 : [
1266 2 : Complex64::new(0.0, 0.0),
1267 2 : Complex64::new(theta.cos(), theta.sin())
1268 2 : ]
1269 2 : ])
1270 2 : }
1271 : }
1272 :
1273 : /// Trait for unitary operations acting on exactly one qubit.
1274 : impl OperateSingleQubitGate for PhaseShiftState1 {
1275 : /// Returns the alpha_r parameter of the operation.
1276 : ///
1277 : /// # Returns
1278 : ///
1279 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
1280 3 : fn alpha_r(&self) -> CalculatorFloat {
1281 3 : (self.theta().clone() / 2.0).cos()
1282 3 : }
1283 : /// Returns the alpha_i parameter of the operation.
1284 : ///
1285 : /// # Returns
1286 : ///
1287 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
1288 3 : fn alpha_i(&self) -> CalculatorFloat {
1289 3 : (self.theta().clone() / 2.0).sin() * (-1.0)
1290 3 : }
1291 : /// Returns the beta_r parameter of the operation.
1292 : ///
1293 : /// # Returns
1294 : ///
1295 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1296 3 : fn beta_r(&self) -> CalculatorFloat {
1297 3 : CalculatorFloat::from(0.0)
1298 3 : }
1299 : /// Returns the beta_i parameter of the operation.
1300 : ///
1301 : /// # Returns
1302 : ///
1303 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1304 3 : fn beta_i(&self) -> CalculatorFloat {
1305 3 : CalculatorFloat::from(0.0)
1306 3 : }
1307 : /// Returns global_phase parameter of the operation.
1308 : ///
1309 : /// # Returns
1310 : ///
1311 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1312 3 : fn global_phase(&self) -> CalculatorFloat {
1313 3 : self.theta().clone() / 2.0
1314 3 : }
1315 : }
1316 :
1317 : /// The phase shift gate applied on state |0>.
1318 : ///
1319 : /// Rotation around Z-axis by an arbitrary angle $\theta$ (AC Stark shift of the state |0>).
1320 : ///
1321 : /// $$
1322 : /// U = \begin{pmatrix}
1323 : /// e^{i \theta} & 0\\\\
1324 : /// 0 & 1
1325 : /// \end{pmatrix}
1326 : /// $$
1327 : ///
1328 : #[derive(
1329 1 : Debug,
1330 9 : Clone,
1331 10 : PartialEq,
1332 3 : roqoqo_derive::InvolveQubits,
1333 35 : roqoqo_derive::Operate,
1334 5 : roqoqo_derive::Substitute,
1335 3 : roqoqo_derive::OperateSingleQubit,
1336 19 : roqoqo_derive::Rotate,
1337 : )]
1338 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1339 : pub struct PhaseShiftState0 {
1340 : /// The qubit the unitary gate is applied to.
1341 : qubit: usize,
1342 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2 \pi$.
1343 : theta: CalculatorFloat,
1344 : }
1345 :
1346 : #[allow(non_upper_case_globals)]
1347 : const TAGS_PhaseShiftState0: &[&str; 5] = &[
1348 : "Operation",
1349 : "GateOperation",
1350 : "SingleQubitGateOperation",
1351 : "Rotation",
1352 : "PhaseShiftState0",
1353 : ];
1354 :
1355 : /// Trait for all operations acting with a unitary gate on a set of qubits.
1356 : impl OperateGate for PhaseShiftState0 {
1357 : /// Returns unitary matrix of the gate.
1358 : ///
1359 : /// # Returns
1360 : ///
1361 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
1362 : /// * `Err(RoqoqoError)` - The parameter conversion to f64 failed (here, not possible).
1363 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
1364 2 : let theta: f64 = f64::try_from(self.theta().clone())?;
1365 2 : Ok(array![
1366 2 : [
1367 2 : Complex64::new(theta.cos(), theta.sin()),
1368 2 : Complex64::new(0.0, 0.0)
1369 2 : ],
1370 2 : [Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)]
1371 2 : ])
1372 2 : }
1373 : }
1374 :
1375 : /// Trait for unitary operations acting on exactly one qubit.
1376 : impl OperateSingleQubitGate for PhaseShiftState0 {
1377 : /// Returns the alpha_r parameter of the operation.
1378 : ///
1379 : /// # Returns
1380 : ///
1381 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
1382 3 : fn alpha_r(&self) -> CalculatorFloat {
1383 3 : (self.theta().clone() / 2.0).cos()
1384 3 : }
1385 : /// Returns the alpha_i parameter of the operation.
1386 : ///
1387 : /// # Returns
1388 : ///
1389 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
1390 3 : fn alpha_i(&self) -> CalculatorFloat {
1391 3 : (self.theta().clone() / 2.0).sin()
1392 3 : }
1393 : /// Returns the beta_r parameter of the operation.
1394 : ///
1395 : /// # Returns
1396 : ///
1397 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1398 3 : fn beta_r(&self) -> CalculatorFloat {
1399 3 : CalculatorFloat::from(0.0)
1400 3 : }
1401 : /// Returns the beta_i parameter of the operation.
1402 : ///
1403 : /// # Returns
1404 : ///
1405 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1406 3 : fn beta_i(&self) -> CalculatorFloat {
1407 3 : CalculatorFloat::from(0.0)
1408 3 : }
1409 : /// Returns global_phase parameter of the operation.
1410 : ///
1411 : /// # Returns
1412 : ///
1413 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1414 3 : fn global_phase(&self) -> CalculatorFloat {
1415 3 : self.theta().clone() / 2.0
1416 3 : }
1417 : }
1418 :
1419 : /// Implements a rotation around an axis in the x-y plane in spherical coordinates.
1420 : ///
1421 : /// $$
1422 : /// U = \begin{pmatrix}
1423 : /// \cos(\frac{\theta}{2}) & 0\\\\
1424 : /// 0 & \cos(\frac{\theta}{2})
1425 : /// \end{pmatrix}
1426 : /// \+ \begin{pmatrix}
1427 : /// -i \sin(\frac{\theta}{2}) v_z & \sin(\frac{\theta}{2}) \left(-i v_x - v_y \right)\\\\
1428 : /// \sin(\frac{\theta}{2}) \left(-i v_x + v_y \right) & i \sin(\frac{\theta}{2}) v_z
1429 : /// \end{pmatrix}
1430 : /// $$
1431 : ///
1432 : /// with
1433 : /// $ v_x = \sin(\theta_{sph}) \cos(\phi_{sph}) $,
1434 : /// $ v_y = \sin(\theta_{sph}) \sin(\phi_{sph}) $,
1435 : /// $ v_z = \cos(\theta_{sph})$.
1436 : ///
1437 : #[derive(
1438 1 : Debug,
1439 11 : Clone,
1440 10 : PartialEq,
1441 3 : roqoqo_derive::InvolveQubits,
1442 3 : roqoqo_derive::Operate,
1443 5 : roqoqo_derive::Substitute,
1444 5 : roqoqo_derive::OperateSingleQubit,
1445 12 : roqoqo_derive::Rotate,
1446 : )]
1447 : #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
1448 : pub struct RotateAroundSphericalAxis {
1449 : /// The qubit the unitary gate is applied to.
1450 : qubit: usize,
1451 : /// The angle $\theta$ of the rotation, in the interval from 0 to $2^* 2 \pi$.
1452 : theta: CalculatorFloat,
1453 : /// The rotation axis, unit-vector spherical coordinates $\theta_{sph}$.
1454 : spherical_theta: CalculatorFloat,
1455 : /// The rotation axis, unit-vector spherical coordinates $\phi_{sph}$ gives the angle in the x-y plane.
1456 : spherical_phi: CalculatorFloat,
1457 : }
1458 :
1459 : #[allow(non_upper_case_globals)]
1460 : const TAGS_RotateAroundSphericalAxis: &[&str; 5] = &[
1461 : "Operation",
1462 : "GateOperation",
1463 : "SingleQubitGateOperation",
1464 : "Rotation",
1465 : "RotateAroundSphericalAxis",
1466 : ];
1467 :
1468 : /// Trait for all operations acting with a unitary gate on a set of qubits.
1469 : impl OperateGate for RotateAroundSphericalAxis {
1470 : /// Returns unitary matrix of the gate.
1471 : ///
1472 : /// # Returns
1473 : ///
1474 : /// * `Ok(Array2<Complex64>)` - The unitary matrix representation of the gate.
1475 : /// * `Err(RoqoqoError)` - The conversion of parameters to f64 failed.
1476 2 : fn unitary_matrix(&self) -> Result<Array2<Complex64>, RoqoqoError> {
1477 2 : let c: f64 = (f64::try_from(self.theta.clone())? / 2.0).cos();
1478 2 : let s: f64 = (f64::try_from(self.theta.clone())? / 2.0).sin();
1479 2 : let vx: f64 = ((f64::try_from(self.spherical_theta.clone())?).sin())
1480 2 : * ((f64::try_from(self.spherical_phi.clone())?).cos());
1481 2 : let vy: f64 = ((f64::try_from(self.spherical_theta.clone())?).sin())
1482 2 : * ((f64::try_from(self.spherical_phi.clone())?).sin());
1483 2 : let vz: f64 = (f64::try_from(self.spherical_theta.clone())?).cos();
1484 2 : Ok(array![
1485 2 : [
1486 2 : Complex64::new(c, -1.0 * s * vz),
1487 2 : Complex64::new(-1.0 * s * vy, -1.0 * s * vx)
1488 2 : ],
1489 2 : [
1490 2 : Complex64::new(s * vy, -1.0 * s * vx),
1491 2 : Complex64::new(c, s * vz)
1492 2 : ]
1493 2 : ])
1494 2 : }
1495 : }
1496 :
1497 : /// Trait for unitary operations acting on exactly one qubit.
1498 : impl OperateSingleQubitGate for RotateAroundSphericalAxis {
1499 : /// Returns the alpha_r parameter of the operation.
1500 : ///
1501 : /// # Returns
1502 : ///
1503 : /// * `alpha_r` - The real part $\alpha_r$ of the on-diagonal elements of the single-qubit unitary matrix.
1504 11 : fn alpha_r(&self) -> CalculatorFloat {
1505 11 : (self.theta.clone() / 2.0).cos()
1506 11 : }
1507 : /// Returns the alpha_i parameter of the operation.
1508 : ///
1509 : /// # Returns
1510 : ///
1511 : /// * `alpha_i` - The imaginary part $ \alpha_i $ of the on-diagonal elements of the single-qubit unitary matrix.
1512 11 : fn alpha_i(&self) -> CalculatorFloat {
1513 11 : let s = (self.theta.clone() / 2.0).sin();
1514 11 : let vz = (self.spherical_theta.clone()).cos();
1515 11 : s * vz * (-1.0) // CHECK sign (?)
1516 11 : }
1517 : /// Returns the beta_r parameter of the operation.
1518 : ///
1519 : /// # Returns
1520 : ///
1521 : /// * `beta_r` - The real part $ \beta_r $ of the off-diagonal elements of the single-qubit unitary matrix.
1522 11 : fn beta_r(&self) -> CalculatorFloat {
1523 11 : let s = (self.theta.clone() / 2.0).sin();
1524 11 : let vy = (self.spherical_phi.clone()).sin();
1525 11 : let st = (self.spherical_theta.clone()).sin();
1526 11 : s * vy * st
1527 11 : }
1528 : /// Returns the beta_i parameter of the operation.
1529 : ///
1530 : /// # Returns
1531 : ///
1532 : /// * `beta_i` - The imaginary part $ \beta_i $ of the off-diagonal elements of the single-qubit unitary matrix.
1533 11 : fn beta_i(&self) -> CalculatorFloat {
1534 11 : let s = (self.theta.clone() / 2.0).sin();
1535 11 : let vx = (self.spherical_phi.clone()).cos();
1536 11 : let st = (self.spherical_theta.clone()).sin();
1537 11 : s * vx * st * (-1.0)
1538 11 : }
1539 : /// Returns global_phase parameter of the operation.
1540 : ///
1541 : /// # Returns
1542 : ///
1543 : /// * `global_phase` - The global phase phi $ \phi $ of the single-qubit unitary.
1544 11 : fn global_phase(&self) -> CalculatorFloat {
1545 11 : CalculatorFloat::from(0.0)
1546 11 : }
1547 : }
|