Skip to main content

Qit/
gates.rs

1/*!
2 Basic gates that make up quantum circuits and traits related to gate applications
3
4 The following gates can act directly on qubits.
5
6* 1-Bit Gates
7    * X(X-Gate. Not Gate)
8    * Y(Y-Gate)
9    * Z(Z-Gate)
10    * H(Hadamard-Gate)
11    * R(R_z-Gate. Gate that rotates at any angle around the z-axis)
12* 2-Bit Gate
13    * CX(Controlled Not Gate)
14* 3-Bit Gate
15    * CCX(Controlled Controlled Not Gate)
16* N-Bit Gate
17    * CNX(Controlled Controlled ...(n) Not Gate)
18
19CNX is an X gate with an arbitrary number of control bits prepared for convenience in circuit creation.
20
21In addition to the above, there is a U structure that combines multiple gates into one circuit,
22and a CU structure that allows you to control multiple gates with one bit.
23
24# Example
25All gates can make changes to the qubit using the apply method.
26## 1-Bit Gates
27```
28use Qit::{gates::{X, Y, Z, H, R}, core::{Applicable, Qubits}};
29use std::f64::consts::PI;
30
31// create gate struct
32let x_0 = X::new(0);
33// make Qbit|000⟩ Qubits::from_num(size: 3, num: 0)
34let q_in = Qubits::from_num(2, 0);
35// apply X-gate to Qbit
36let q_out = x_0.apply(q_in);
37
38q_out.print_probs();
39// |00⟩ : +0.000 +0.000i
40// |01⟩ : +1.000 +0.000i
41// |10⟩ : +0.000 +0.000i
42// |11⟩ : +0.000 +0.000i
43
44// Y-Gate
45let y_0 = Y::new(0);
46let q_in = Qubits::zeros(2);
47let q_out = y_0.apply(q_in);
48q_out.print_cmps();
49// |00⟩ : +0.000 +0.000i
50// |01⟩ : +0.000 -1.000i
51// |10⟩ : +0.000 +0.000i
52// |11⟩ : +0.000 +0.000i
53
54// Z-Gate
55let z_0 = Z::new(0);
56let q_in = Qubits::from_num(2, 1);
57let q_out = z_0.apply(q_in);
58q_out.print_cmps();
59// |00⟩ : +0.000 +0.000i
60// |01⟩ : -1.000 -0.000i
61// |10⟩ : +0.000 +0.000i
62// |11⟩ : -0.000 -0.000i
63
64// Hadamard-Gate
65let h_0 = H::new(0);
66let q_in = Qubits::zeros(2);
67let q_out = h_0.apply(q_in);
68q_out.print_cmps();
69// |00⟩ : +0.707 +0.000i
70// |01⟩ : +0.707 +0.000i
71// |10⟩ : +0.000 +0.000i
72// |11⟩ : +0.000 +0.000i
73
74// R gate requires angle of f64.
75let angle = 0.5 * PI;
76let r_0 = R::new(0, angle);
77let q_in = q_out;
78let q_out = r_0.apply(q_in);
79q_out.print_cmps();
80// |00⟩ : +0.707 +0.000i
81// |01⟩ : +0.000 +0.707i
82// |10⟩ : +0.000 +0.000i
83// |11⟩ : +0.000 +0.000i
84
85```
86
87## 2-Bit Gate
88```
89use Qit::core::{Applicable, Qubits, Comp};
90use Qit::gates::CX;
91
92// create CX(0 → 1)
93let cx01 = CX::new(0, 1);
94let q_in = Qubits::from_num(2, 1);
95let q_out = cx01.apply(q_in);
96q_out.print_cmps();
97// |00⟩ : +0.000 +0.000i
98// |01⟩ : +0.000 +0.000i
99// |10⟩ : +0.000 +0.000i
100// |11⟩ : +1.000 +0.000i
101assert_eq!(q_out.bits[0b11], Comp::new(1.0, 0.0));
102```
103
104## 3-Bit Gate
105```
106use Qit::core::{Applicable, Comp, Qubits};
107use Qit::gates::CCX;
108
109let ccx = CCX::new(0, 1, 2);
110// q_in = |011⟩
111let q_in = Qubits::from_num(3, 3);
112let q_out = ccx.apply(q_in);
113q_out.print_cmps();
114// |000⟩ : +0.000 +0.000i
115// |001⟩ : +0.000 +0.000i
116// |010⟩ : +0.000 +0.000i
117// |011⟩ : +0.000 +0.000i
118// |100⟩ : +0.000 +0.000i
119// |101⟩ : +0.000 +0.000i
120// |110⟩ : +0.000 +0.000i
121// |111⟩ : +1.000 +0.000i
122assert_eq!(q_out.bits[0b111], Comp::new(1.0, 0.0));
123```
124
125## n-Bit Gate
126```
127use Qit::core::{Applicable, Comp, Qubits};
128use Qit::gates::CNX;
129
130let cnx = CNX::new(vec![0, 1, 2], 3);
131// q_in = |0111⟩
132let q_in = Qubits::from_num(4, 7);
133let q_out = cnx.apply(q_in);
134q_out.print_cmps();
135// |0000⟩ : +0.000 +0.000i
136// |0001⟩ : +0.000 +0.000i
137//        .
138//        .
139//        .
140// |1110⟩ : +0.000 +0.000i
141// |1111⟩ : +1.000 +0.000i
142assert_eq!(q_out.bits[0b1111], Comp::new(1.0, 0.0));
143```
144*/
145
146use std::f64::consts::{PI, SQRT_2};
147
148use super::core::{Applicable, BitSlideIndex, Comp, Inversible, Operator, Qubits};
149
150const SQRT2_INV: f64 = 1.0 / SQRT_2;
151
152/**
153 * Hadamard Gate. 1√2(|0⟩⟨0| + |1⟩⟨0| + |0⟩⟨1| - |1⟩⟨1|)
154
155 # Usage
156 ```
157use Qit::{gates::H, core::{Applicable, Qubits}};
158
159// Hadamard-Gate
160let h_0 = H::new(0);
161let q_in = Qubits::zeros(2);
162let q_out = h_0.apply(q_in);
163q_out.print_cmps();
164// |00⟩ : +0.707 +0.000i
165// |01⟩ : +0.707 +0.000i
166// |10⟩ : +0.000 +0.000i
167// |11⟩ : +0.000 +0.000i
168 ```
169
170*/
171#[derive(Clone, Copy)]
172pub struct H {
173    target_bit: usize,
174}
175
176impl H {
177    pub fn new(target_bit: usize) -> Self {
178        return H {
179            target_bit: target_bit,
180        };
181    }
182}
183
184impl Applicable for H {
185    fn name(&self) -> String {
186        return format!("H({})", self.target_bit);
187    }
188
189    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
190        let step = 1 << self.target_bit;
191        let iter = iter.merge(step);
192
193        for idx1 in iter {
194            let idx0 = idx1 - step;
195            let temp = qubits.bits[idx0];
196            qubits.bits[idx0] = (qubits.bits[idx1] + temp) * SQRT2_INV;
197            qubits.bits[idx1] = (temp - qubits.bits[idx1]) * SQRT2_INV;
198        }
199
200        return qubits;
201    }
202}
203
204impl Inversible for H {}
205impl Operator for H {}
206
207/**
208Not Gate(pauli-X). (|1⟩⟨0| + |0⟩⟨1|)
209
210# Usage
211```
212use Qit::{gates::X, core::{Applicable, Qubits}};
213
214// X-Gate
215let x_0 = X::new(0);
216let q_in = Qubits::from_num(2, 0);
217let q_out = x_0.apply(q_in);
218q_out.print_probs();
219// |00⟩ : +0.000 +0.000i
220// |01⟩ : +1.000 +0.000i
221// |10⟩ : +0.000 +0.000i
222// |11⟩ : +0.000 +0.000i
223```
224*/
225#[derive(Clone, Copy)]
226pub struct X {
227    target_bit: usize,
228}
229impl X {
230    pub fn new(target_bit: usize) -> Self {
231        return X {
232            target_bit: target_bit,
233        };
234    }
235}
236
237impl Applicable for X {
238    fn name(&self) -> String {
239        return format!("X({})", self.target_bit);
240    }
241
242    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
243        let step = 1 << self.target_bit;
244        let iter = iter.merge(step);
245
246        for idx1 in iter {
247            let idx0 = idx1 - step;
248            let temp = qubits.bits[idx0];
249            qubits.bits[idx0] = qubits.bits[idx1];
250            qubits.bits[idx1] = temp;
251        }
252
253        return qubits;
254    }
255}
256
257impl Inversible for X {}
258impl Operator for X {}
259
260/**
261 pauli-Y Gate. i(|1⟩⟨0| - |0⟩⟨1|)
262
263# Usage
264```
265use Qit::{gates::Y, core::{Applicable, Qubits}};
266
267// Y-Gate
268let y_0 = Y::new(0);
269let q_in = Qubits::zeros(2);
270let q_out = y_0.apply(q_in);
271q_out.print_cmps();
272// |00⟩ : +0.000 +0.000i
273// |01⟩ : +0.000 -1.000i
274// |10⟩ : +0.000 +0.000i
275// |11⟩ : +0.000 +0.000i
276```
277*/
278#[derive(Clone, Copy)]
279pub struct Y {
280    target_bit: usize,
281}
282
283impl Y {
284    pub fn new(target_bit: usize) -> Self {
285        return Y {
286            target_bit: target_bit,
287        };
288    }
289}
290
291impl Applicable for Y {
292    fn name(&self) -> String {
293        return format!("Y({})", self.target_bit);
294    }
295
296    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
297        let step = 1 << self.target_bit;
298        let iter = iter.merge(step);
299
300        for idx1 in iter {
301            let idx0 = idx1 - step;
302            let temp = qubits.bits[idx0];
303            qubits.bits[idx0] = Comp::new(0.0, 1.0) * qubits.bits[idx1];
304            qubits.bits[idx1] = Comp::new(0.0, -1.0) * temp;
305        }
306
307        return qubits;
308    }
309}
310
311impl Inversible for Y {}
312impl Operator for Y {}
313
314/**
315 pauli-Z Gate. (|0⟩⟨0| - |1⟩⟨1|)
316
317 # Usage
318
319 ```
320use Qit::{gates::Z, core::{Applicable, Qubits}};
321
322// Z-Gate
323let z_0 = Z::new(0);
324let q_in = Qubits::from_num(2, 1);
325let q_out = z_0.apply(q_in);
326q_out.print_cmps();
327// |00⟩ : +0.000 +0.000i
328// |01⟩ : -1.000 -0.000i
329// |10⟩ : +0.000 +0.000i
330// |11⟩ : -0.000 -0.000i
331 ```
332*/
333#[derive(Clone, Copy)]
334pub struct Z {
335    target_bit: usize,
336}
337
338impl Z {
339    pub fn new(target_bit: usize) -> Self {
340        return Z {
341            target_bit: target_bit,
342        };
343    }
344}
345
346impl Applicable for Z {
347    fn name(&self) -> String {
348        return format!("Z({})", self.target_bit);
349    }
350
351    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
352        let step = 1 << self.target_bit;
353        let iter = iter.merge(step);
354
355        for idx1 in iter {
356            qubits.bits[idx1] = qubits.bits[idx1] * -1.0;
357        }
358
359        return qubits;
360    }
361}
362
363impl Inversible for Z {}
364impl Operator for Z {}
365
366/**
367Phase shift Gate. (|0⟩⟨0| + exp(ir)|1⟩⟨1|)
368
369(|0⟩ + |1⟩)  →R(π)→  (|0⟩ - |1⟩)
370
371(|0⟩ + |1⟩)  →R(π/2)→  (|0⟩ + i|1⟩)
372
373# Usage
374```
375use Qit::{gates::R, core::{Applicable, Qubits, Comp}};
376use std::f64::consts::PI;
377
378// R gate requires angle of f64.
379let angle = 0.5 * PI;
380let r_0 = R::new(0, angle);
381let q_in = Qubits::from_num(2, 1);
382let q_out = r_0.apply(q_in);
383q_out.print_cmps();
384// |00⟩ : +0.000 +0.000i
385// |01⟩ : +0.000 +1.000i
386// |10⟩ : +0.000 +0.000i
387// |11⟩ : +0.000 +0.000i
388```
389 */
390#[derive(Clone, Copy)]
391pub struct R {
392    target_bit: usize,
393    angle: f64,
394    phase: Comp,
395}
396
397impl R {
398    pub fn new(target_bit: usize, angle: f64) -> Self {
399        let phase = Comp(angle.cos(), angle.sin());
400        return R {
401            target_bit: target_bit,
402            angle: angle,
403            phase: phase,
404        };
405    }
406}
407
408impl Applicable for R {
409    fn name(&self) -> String {
410        return format!("R_{}({})", self.angle, self.target_bit);
411    }
412
413    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
414        let step = 1 << self.target_bit;
415        let iter = iter.merge(step);
416        for idx1 in iter {
417            qubits.bits[idx1] = qubits.bits[idx1] * self.phase;
418        }
419
420        return qubits;
421    }
422}
423
424impl Inversible for R {
425    fn inverse(&mut self) {
426        self.angle = 2.0 * PI - self.angle;
427        self.phase = Comp(self.angle.cos(), self.angle.sin());
428    }
429}
430impl Operator for R {}
431
432/**
433Controlled-Not Gate.
434
435# Usage
436
437```
438use Qit::core::{Applicable, Qubits, Comp};
439use Qit::gates::CX;
440
441// create CX(0 → 1)
442let cx01 = CX::new(0, 1);
443let q_in = Qubits::from_num(2, 1);
444let q_out = cx01.apply(q_in);
445q_out.print_cmps();
446// |00⟩ : +0.000 +0.000i
447// |01⟩ : +0.000 +0.000i
448// |10⟩ : +0.000 +0.000i
449// |11⟩ : +1.000 +0.000i
450assert_eq!(q_out.bits[0b11], Comp::new(1.0, 0.0));
451```
452 */
453#[derive(Clone, Copy)]
454pub struct CX {
455    controll_bit: usize,
456    target_bit: usize,
457}
458
459impl CX {
460    pub fn new(controll_bit: usize, target_bit: usize) -> Self {
461        return CX {
462            controll_bit: controll_bit,
463            target_bit: target_bit,
464        };
465    }
466}
467
468impl Applicable for CX {
469    fn name(&self) -> String {
470        return format!("CX({}->{})", self.controll_bit, self.target_bit);
471    }
472    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
473        let step = 1 << self.target_bit;
474        let iter = iter.merge((1 << self.controll_bit) | step);
475
476        for idx1 in iter {
477            let idx0 = idx1 - step;
478            let temp = qubits.bits[idx0];
479            qubits.bits[idx0] = qubits.bits[idx1];
480            qubits.bits[idx1] = temp;
481        }
482
483        return qubits;
484    }
485}
486
487impl Inversible for CX {}
488impl Operator for CX {}
489
490/**
491Controlled-Controlled-Not(CXX) Gate.
492
493# Usage
494
495```
496use Qit::core::{Applicable, Comp, Qubits};
497use Qit::gates::CCX;
498
499let ccx = CCX::new(0, 1, 2);
500// q_in = |011⟩
501let q_in = Qubits::from_num(3, 3);
502let q_out = ccx.apply(q_in);
503q_out.print_cmps();
504// |000⟩ : +0.000 +0.000i
505// |001⟩ : +0.000 +0.000i
506// |010⟩ : +0.000 +0.000i
507// |011⟩ : +0.000 +0.000i
508// |100⟩ : +0.000 +0.000i
509// |101⟩ : +0.000 +0.000i
510// |110⟩ : +0.000 +0.000i
511// |111⟩ : +1.000 +0.000i
512assert_eq!(q_out.bits[0b111], Comp::new(1.0, 0.0));
513```
514 */
515#[derive(Clone, Copy)]
516pub struct CCX {
517    controll_bit1: usize,
518    controll_bit2: usize,
519    target_bit: usize,
520}
521
522impl CCX {
523    pub fn new(controll_bit1: usize, controll_bit2: usize, target_bit: usize) -> Self {
524        return CCX {
525            controll_bit1: controll_bit1,
526            controll_bit2: controll_bit2,
527            target_bit: target_bit,
528        };
529    }
530}
531
532impl Applicable for CCX {
533    fn name(&self) -> String {
534        return format!(
535            "CCX([{},{}]->{})",
536            self.controll_bit1, self.controll_bit2, self.target_bit
537        );
538    }
539    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
540        let step = 1 << self.target_bit;
541        let iter = iter.merge((1 << self.controll_bit1) | (1 << self.controll_bit2) | step);
542
543        for idx1 in iter {
544            let idx0 = idx1 - step;
545            let temp = qubits.bits[idx0];
546            qubits.bits[idx0] = qubits.bits[idx1];
547            qubits.bits[idx1] = temp;
548        }
549
550        return qubits;
551    }
552}
553
554impl Inversible for CCX {}
555impl Operator for CCX {}
556
557/**
558Controlled-Controlled-Controlled-...(N)-Not Gate
559
560# Usage
561```
562use Qit::core::{Applicable, Comp, Qubits};
563use Qit::gates::CNX;
564
565let cnx = CNX::new(vec![0, 1, 2], 3);
566// q_in = |0111⟩
567let q_in = Qubits::from_num(4, 7);
568let q_out = cnx.apply(q_in);
569q_out.print_cmps();
570// |0000⟩ : +0.000 +0.000i
571// |0001⟩ : +0.000 +0.000i
572//        .
573//        .
574//        .
575// |1110⟩ : +0.000 +0.000i
576// |1111⟩ : +1.000 +0.000i
577assert_eq!(q_out.bits[0b1111], Comp::new(1.0, 0.0));
578```
579*/
580#[derive(Clone)]
581pub struct CNX {
582    controll_bits: Vec<usize>,
583    target_bit: usize,
584}
585
586impl CNX {
587    pub fn new(controll_bits: Vec<usize>, target_bit: usize) -> Self {
588        return CNX {
589            controll_bits: controll_bits,
590            target_bit: target_bit,
591        };
592    }
593
594    fn cbit_mask(&self) -> usize {
595        let mut mask = 0;
596        for cbit in self.controll_bits.iter() {
597            mask |= 1 << (*cbit);
598        }
599        return mask;
600    }
601}
602
603impl Applicable for CNX {
604    fn name(&self) -> String {
605        let mut s = String::from("CNX[");
606        for i in self.controll_bits.iter() {
607            s += &format!("{},", i);
608        }
609        s += &format!("]->{}", self.target_bit);
610        return s;
611    }
612    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
613        let step = 1 << self.target_bit;
614        let iter = iter.merge(self.cbit_mask() | step);
615
616        for idx1 in iter {
617            let idx0 = idx1 - step;
618            let temp = qubits.bits[idx0];
619            qubits.bits[idx0] = qubits.bits[idx1];
620            qubits.bits[idx1] = temp;
621        }
622
623        return qubits;
624    }
625}
626
627impl Inversible for CNX {}
628impl Operator for CNX {}
629
630/**
631An alias for handling quantum gates together.
632
633# Example
634
635```
636use Qit::core::{Applicable, Qubits};
637use Qit::gates::{OperatorVec, PushOps, H, U};
638
639let mut v = OperatorVec::new();
640v.push_ops(H::new(0));
641v.push_ops(H::new(1));
642let u = U::new(v, String::from("hadamards"));
643let q_in = Qubits::from_num(2, 0);
644let q_out = u.apply(q_in);
645
646q_out.print_cmps();
647// |00⟩ : +0.500 +0.000i
648// |01⟩ : +0.500 +0.000i
649// |10⟩ : +0.500 +0.000i
650// |11⟩ : +0.500 +0.000i
651```
652*/
653pub type OperatorVec = Vec<Box<dyn Operator>>;
654
655/**
656A trait to make adding gates as easy as possible.
657 */
658pub trait PushOps {
659    fn push_ops(&mut self, op: impl Operator + 'static);
660}
661
662impl PushOps for OperatorVec {
663    fn push_ops(&mut self, op: impl Operator + 'static) {
664        self.push(Box::new(op));
665    }
666}
667
668// CU
669/**
670Controlled-Unitary Gate.
671Control a group of arbitrary gates using a specific qubit.
672
673```
674use Qit::circuits::wrapping_qadd_const;
675use Qit::core::{Applicable, Comp, Operator, Qubits};
676use Qit::gates::{CU, OperatorVec, PushOps};
677
678// make controlled-add_3
679let b_in = vec![0, 1, 2];
680let controll_bit = 3;
681
682let add_3 = wrapping_qadd_const(&b_in, 3);
683let controlled_add_3 = CU::from_u(controll_bit, add_3);
684
685// or
686let add_3 = wrapping_qadd_const(&b_in, 3);
687let add_3_gates: OperatorVec = add_3.gates;
688let controlled_add_3 = CU::new(
689    controll_bit,
690    add_3_gates,
691    String::from("something_name_you_like"),
692);
693
694// q_in = |1001⟩
695let q_in = Qubits::from_num(4, 0b1001);
696let q_out = controlled_add_3.apply(q_in);
697q_out.print_cmps();
698// |0000⟩ : +0.000 +0.000i
699//        .
700//        .
701//        .
702// |1011⟩ : +0.000 +0.000i
703// |1100⟩ : +1.000 +0.000i
704// |1101⟩ : +0.000 +0.000i
705// |1110⟩ : +0.000 +0.000i
706// |1111⟩ : +0.000 +0.000i
707```
708*/
709pub struct CU {
710    controll_bit: usize,
711    gates: OperatorVec,
712    label: String,
713}
714
715impl CU {
716    pub fn new(controll_bit: usize, gates: OperatorVec, label: String) -> Self {
717        return CU {
718            controll_bit: controll_bit,
719            gates: gates,
720            label: label,
721        };
722    }
723
724    pub fn from_u(controll_bit: usize, u: U) -> Self {
725        return CU {
726            controll_bit: controll_bit,
727            gates: u.gates,
728            label: u.label,
729        };
730    }
731}
732
733impl Applicable for CU {
734    fn name(&self) -> String {
735        let mut s = format!("CU({}->", self.controll_bit);
736        for gate in &self.gates {
737            s.push_str(&format!("\n{}", gate.name()));
738        }
739        return format!("{})", s);
740    }
741
742    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
743        let iter = iter.merge(1 << self.controll_bit);
744        for gate in &self.gates {
745            qubits = gate.apply_iter(qubits, &iter);
746        }
747
748        return qubits;
749    }
750}
751
752impl Inversible for CU {
753    fn inverse(&mut self) {
754        for g in self.gates.iter_mut() {
755            g.inverse();
756        }
757        self.gates.reverse();
758    }
759}
760
761impl Operator for CU {}
762
763/**
764Unitary struct. struct for applying a vector of arbitrary gates together to a qubit
765
766# Example usage
767```
768use Qit::{gates::*};
769// full adder
770let a_in = 0;
771let b_in = 1;
772let c_in = 2;
773let c_out = 3;
774let ccx1 = CCX::new(a_in, b_in, c_out);
775let cx1 = CX::new(a_in, b_in);
776let ccx2 = CCX::new(b_in, c_in, c_out);
777let cx2 = CX::new(c_in, b_in);
778let adder = U::new(vec![Box::new(ccx1), Box::new(cx1), Box::new(ccx2), Box::new(cx2)],
779        String::from("full_adder_bit"));
780```
781 */
782pub struct U {
783    pub gates: OperatorVec,
784    label: String,
785}
786
787impl U {
788    pub fn new(gates: OperatorVec, name: String) -> Self {
789        return U {
790            gates: gates,
791            label: name,
792        };
793    }
794
795    pub fn rename(&mut self, name: String) {
796        self.label = name;
797    }
798}
799
800impl Applicable for U {
801    fn name(&self) -> String {
802        let mut s = format!("U[{}](", self.label);
803        for gate in &self.gates {
804            s.push_str(&format!("\n{}", gate.name()));
805        }
806        return format!("{})", s);
807    }
808
809    fn apply_iter(&self, mut qubits: Qubits, iter: &BitSlideIndex) -> Qubits {
810        for gate in &self.gates {
811            qubits = gate.apply_iter(qubits, &iter);
812        }
813
814        return qubits;
815    }
816}
817
818impl Inversible for U {
819    fn inverse(&mut self) {
820        for g in self.gates.iter_mut() {
821            g.inverse();
822        }
823        self.gates.reverse();
824    }
825}
826
827impl Operator for U {}