q1tsim/gates/
controlled.rs

1// Copyright 2019 Q1t BV
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::gates::{Gate, CX};
16
17/// Controlled gates.
18///
19/// A controlled gate is a gate which acts upon a control bit: when
20/// the control bit is zero, it leaves the target unchanged; when the control
21/// bit is one, the gate is applied.
22pub struct C<G>
23where G: crate::gates::Gate
24{
25    gate: G,
26    desc: String
27}
28
29impl<G> C<G>
30where G: crate::gates::Gate
31{
32    /// Create a new controlled gate for `gate`.
33    pub fn new(gate: G) -> Self
34    {
35        let desc = format!("C{}", gate.description());
36        C { gate: gate, desc: desc }
37    }
38}
39
40impl<G> crate::gates::Gate for C<G>
41where G: crate::gates::Gate
42{
43    fn cost(&self) -> f64
44    {
45        // Wild guess, probably wildly wrong
46        2.0 * self.gate.cost()
47    }
48
49    fn description(&self) -> &str
50    {
51        &self.desc
52    }
53
54    fn nr_affected_bits(&self) -> usize
55    {
56        1 + self.gate.nr_affected_bits()
57    }
58
59    fn matrix(&self) -> crate::cmatrix::CMatrix
60    {
61        let gm = self.gate.matrix();
62        let gsize = gm.rows();
63
64        let mut res = crate::cmatrix::CMatrix::eye(2*gsize);
65        res.slice_mut(s![gsize.., gsize..]).assign(&gm);
66
67        res
68    }
69
70    fn apply_slice(&self, mut state: crate::cmatrix::CVecSliceMut)
71    {
72        let n = state.len() / 2;
73        self.gate.apply_slice(state.slice_mut(s![n..]));
74    }
75
76    fn apply_mat_slice(&self, mut state: crate::cmatrix::CMatSliceMut)
77    {
78        let n = state.rows() / 2;
79        self.gate.apply_mat_slice(state.slice_mut(s![n.., ..]));
80    }
81}
82
83impl<G> crate::export::Latex for C<G>
84where G: crate::gates::Gate + crate::export::Latex
85{
86    fn latex(&self, bits: &[usize], state: &mut crate::export::LatexExportState)
87        -> crate::error::Result<()>
88    {
89        self.check_nr_bits(bits.len())?;
90
91        state.start_range_op(bits, None)?;
92
93        // We can only reasonably draw this if the controlled gate
94        // operates on bits all above or all below the control bit
95        let control = bits[0];
96        let min = *bits[1..].iter().min().unwrap();
97        let max = *bits[1..].iter().max().unwrap();
98        if min > control && max > control
99        {
100            state.set_field(control, format!(r"\ctrl{{{}}}", min - control))?;
101        }
102        else if min < control && max < control
103        {
104            state.set_field(control, format!(r"\ctrl{{{}}}", max as isize - control as isize))?;
105        }
106        else
107        {
108            // XXX FIXME: figure out how to do this, and if really not possible,
109            // return an error.
110            panic!("Unable to draw controlled gate with control in the middle");
111        }
112
113        let controlled = state.set_controlled(true);
114        self.gate.latex(&bits[1..], state)?;
115        state.set_controlled(controlled);
116
117        state.end_range_op();
118
119        Ok(())
120    }
121}
122
123#[macro_export]
124macro_rules! declare_controlled_type
125{
126    ($(#[$attr:meta])* $name:ident, $gate_type:ty $(, $arg:ident)*) => {
127        $(#[$attr])*
128        pub struct $name
129        {
130            $( #[allow(dead_code)] $arg: $crate::gates::Parameter, )*
131            cgate: $crate::gates::C<$gate_type>
132        }
133    }
134}
135
136// XXX FIXME: we need a proper fix for declaring controlled parametrized gates
137// with an arbitrary number of (possible reference) parameters. This currently
138// only supports using reference parameters in single-parameter gates.
139#[macro_export]
140macro_rules! declare_controlled_impl
141{
142    ($name:ident, $gate_type:ty, $arg:ident) => {
143        impl $name
144        {
145            pub fn new<T>($arg: T) -> Self
146            where T: Clone, $crate::gates::Parameter: From<T>
147            {
148                $name
149                {
150                    $arg: $crate::gates::Parameter::from($arg.clone()),
151                    cgate: $crate::gates::C::new(<$gate_type>::new($arg))
152                }
153            }
154        }
155    };
156    ($name:ident, $gate_type:ty $(, $arg:ident)*) => {
157        impl $name
158        {
159            pub fn new($($arg: f64, )*) -> Self
160            {
161                $name
162                {
163                    $( $arg: $crate::gates::Parameter::from($arg), )*
164                    cgate: $crate::gates::C::new(<$gate_type>::new($($arg, )*))
165                }
166            }
167        }
168    };
169    ($name:ident, $gate_type:ty, cost=$cost:expr, $arg:ident) => {
170        impl $name
171        {
172            pub fn new<T>($arg: T) -> Self
173            where T: Clone, $crate::gates::Parameter: From<T>
174            {
175                $name
176                {
177                    $arg: $crate::gates::Parameter::from($arg.clone()),
178                    cgate: $crate::gates::C::new(<$gate_type>::new($arg))
179                }
180            }
181            pub fn cost() -> f64
182            {
183                $cost
184            }
185        }
186    };
187    ($name:ident, $gate_type:ty, cost=$cost:expr $(, $arg:ident)*) => {
188        impl $name
189        {
190            pub fn new($($arg: f64, )*) -> Self
191            {
192                $name
193                {
194                    $( $arg: $crate::gates::Parameter::from($arg), )*
195                    cgate: $crate::gates::C::new(<$gate_type>::new($($arg, )*))
196                }
197            }
198            pub fn cost() -> f64
199            {
200                $cost
201            }
202        }
203    };
204}
205
206#[macro_export]
207macro_rules! declare_controlled_cost
208{
209    ($cost:expr) => {
210        fn cost(&self) -> f64 { $cost }
211    };
212    () => {
213        fn cost(&self) -> f64 { self.cgate.cost() }
214    };
215}
216
217#[macro_export]
218macro_rules! declare_controlled_qasm
219{
220    ($trait_name:ident, $gate_name:ident, $method_name:ident $(, arg=$arg:ident)*) => {
221        impl $crate::export::$trait_name for $gate_name
222        {
223            fn $method_name(&self, bit_names: &[String], bits: &[usize])
224                -> $crate::error::Result<String>
225            {
226                let mut res = stringify!($gate_name).to_lowercase();
227                let args: Vec<String> = vec![
228                    $(
229                        format!("{}", self.$arg),
230                    )*
231                ];
232                if stringify!($trait_name) == "OpenQasm"
233                {
234                    if !args.is_empty()
235                    {
236                        res += "(";
237                        res += &args.join(", ");
238                        res += ")";
239                    }
240                }
241                if bits.len() > 0
242                {
243                    res += &format!(" {}", bit_names[bits[0]]);
244                    for &bit in bits[1..].iter()
245                    {
246                        res += &format!(", {}", &bit_names[bit]);
247                    }
248                }
249                if stringify!($trait_name) == "CQasm"
250                {
251                    if !args.is_empty()
252                    {
253                        res += ", ";
254                        res += &args.join(", ");
255                    }
256                }
257                Ok(res)
258            }
259        }
260    };
261    ($trait_name:ident, $gate_name:ident, $method_name: ident, qasm=$qasm:expr $(, arg=$arg:ident)*) => {
262        impl $crate::export::$trait_name for $gate_name
263        {
264            fn $method_name(&self, bit_names: &[String], bits: &[usize])
265                -> $crate::error::Result<String>
266            {
267                let mut res = String::from($qasm);
268                for (i, &bit) in bits.iter().enumerate()
269                {
270                    let pattern = format!("{{{}}}", i);
271                    res = res.replace(&pattern, &bit_names[bit]);
272                }
273                $(
274                    let pattern = concat!("{", stringify!($arg), "}");
275                    res = res.replace(pattern, &self.$arg.to_string());
276                )*
277
278                let mut off = 0;
279                while let Some(i) = res[off..].find('{')
280                {
281                    let istart = off + i;
282                    if let Some(len) = res[istart..].find('}')
283                    {
284                        let iend = istart + len + 1;
285                        let replacement;
286                        match crate::gates::Composite::parse_sum_expression(&res[istart+1..iend-1])
287                        {
288                            Ok((val, "")) => { replacement = Some(val.to_string()); },
289                            _             => { replacement = None; }
290                        }
291                        if let Some(repl) = replacement
292                        {
293                            res.replace_range(istart..iend, &repl);
294                        }
295                    }
296
297                    off = istart + 1;
298                }
299
300                Ok(res)
301            }
302        }
303    };
304}
305
306#[macro_export]
307macro_rules! declare_controlled_latex
308{
309    ($gate_name:ident) => {
310        impl $crate::export::Latex for $gate_name
311        {
312            fn latex(&self, bits: &[usize], state: &mut $crate::export::LatexExportState)
313                -> $crate::error::Result<()>
314            {
315                self.cgate.latex(bits, state)
316            }
317        }
318    }
319}
320
321#[macro_export]
322macro_rules! declare_controlled_impl_gate
323{
324    ($name:ident, $gate_type:ty $(, cost=$cost:expr)*) => {
325        impl $crate::gates::Gate for $name
326        {
327            declare_controlled_cost!($($cost)*);
328            fn description(&self) -> &str { self.cgate.description() }
329            fn nr_affected_bits(&self) -> usize { self.cgate.nr_affected_bits() }
330            fn matrix(&self) -> $crate::cmatrix::CMatrix { self.cgate.matrix() }
331            fn apply_slice(&self, state: $crate::cmatrix::CVecSliceMut)
332            {
333                self.cgate.apply_slice(state);
334            }
335            fn apply_mat_slice(&self, state: $crate::cmatrix::CMatSliceMut)
336            {
337                self.cgate.apply_mat_slice(state);
338            }
339        }
340    };
341}
342
343#[macro_export]
344macro_rules! declare_controlled
345{
346    ($(#[$attr:meta])* $name:ident, $gate_type:ty) => {
347        declare_controlled_type!($(#[$attr])* $name, $gate_type);
348        declare_controlled_impl!($name, $gate_type);
349        declare_controlled_impl_gate!($name, $gate_type);
350        declare_controlled_qasm!(OpenQasm, $name, open_qasm);
351        declare_controlled_qasm!(CQasm, $name, c_qasm);
352        declare_controlled_latex!($name);
353    };
354    ($(#[$attr:meta])* $name:ident, $gate_type:ty, cost=$cost:expr $(, arg=$arg:ident)* $(, open_qasm=$open_qasm:expr)* $(, c_qasm=$c_qasm:expr)*) => {
355        declare_controlled_type!($(#[$attr])* $name, $gate_type $(, $arg)*);
356        declare_controlled_impl!($name, $gate_type, cost=$cost $(, $arg)*);
357        declare_controlled_impl_gate!($name, $gate_type, cost=Self::cost());
358        declare_controlled_qasm!(OpenQasm, $name, open_qasm $(, qasm=$open_qasm)* $(, arg=$arg)*);
359        declare_controlled_qasm!(CQasm, $name, c_qasm $(, qasm=$c_qasm)* $(, arg=$arg)*);
360        declare_controlled_latex!($name);
361    };
362}
363
364declare_controlled!(
365    /// Controlled Hadamard gate.
366    CH, crate::gates::H,
367    cost=2.0*CX::cost() + 5.0*crate::gates::U1::cost() + 3.0*crate::gates::U2::cost() + crate::gates::U3::cost());
368
369declare_controlled!(
370    /// Controlled `R`<sub>`X`</sub> gate.
371    CRX, crate::gates::RX,
372    cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost(),
373    arg=theta,
374    open_qasm="s {1}; cx {0}, {1}; ry(-{theta}/2) {1}; cx {0}, {1}; ry({theta}/2) {1}; sdg {1}",
375    c_qasm=r#"s {1}
376cnot {0}, {1}
377ry {1}, {-0.5 * {theta}}
378cnot {0}, {1}
379ry {1}, {0.5 * {theta}}
380sdag {1}"#);
381declare_controlled!(
382    /// Controlled `R`<sub>`Y`</sub> gate.
383    CRY, crate::gates::RY,
384    cost=2.0*CX::cost() + 2.0*crate::gates::U3::cost(),
385    arg=theta,
386    open_qasm="cx {0}, {1}; u3(-{theta}/2, 0, 0) {1}; cx {0}, {1}; u3({theta}/2, 0, 0) {1}",
387    c_qasm="cnot {0}, {1}\nry {1}, -{0.5 * {theta}}\ncnot {0}, {1}\nry {1}, {0.5 * {theta}}");
388declare_controlled!(
389    /// Controlled `R`<sub>`Z`</sub> gate.
390    CRZ, crate::gates::RZ,
391    cost=2.0*CX::cost() + 2.0*crate::gates::U1::cost(),
392    arg=lambda);
393
394declare_controlled!(
395    /// Controlled `S` gate.
396    CS, crate::gates::S, cost=2.0*CX::cost() + 3.0*crate::gates::U1::cost(),
397    open_qasm="cu1(pi/2) {0}, {1}",
398    c_qasm="crk {0}, {1}, 1");
399declare_controlled!(
400    /// Controlled `S`<sup>`†`</sup> gate.
401    CSdg, crate::gates::Sdg, cost=2.0*CX::cost() + 3.0*crate::gates::U1::cost(),
402    open_qasm="cu1(-pi/2) {0}, {1}",
403    c_qasm="cr {0}, {1}, -1.570796326794897");
404
405declare_controlled!(
406    /// Controlled `T` gate.
407    CT, crate::gates::T, cost=2.0*CX::cost() + 3.0*crate::gates::U1::cost(),
408    open_qasm="cu1(pi/4) {0}, {1}",
409    c_qasm="crk {0}, {1}, 2");
410declare_controlled!(
411    /// Controlled `T`<sup>`†`</sup> gate.
412    CTdg, crate::gates::Tdg, cost=2.0*CX::cost() + 3.0*crate::gates::U1::cost(),
413    open_qasm="cu1(-pi/4) {0}, {1}",
414    c_qasm="cr {0}, {1}, -0.7853981633974483");
415
416declare_controlled!(
417    /// Controlled `U`<sub>`1`</sub> gate.
418    CU1, crate::gates::U1,
419    cost=2.0*CX::cost() + 3.0*crate::gates::U1::cost(),
420    arg=lambda,
421    c_qasm="cr {0}, {1}, {lambda}");
422declare_controlled!(
423    /// Controlled `U`<sub>`2`</sub> gate.
424    CU2, crate::gates::U2,
425    cost=2.0*CX::cost() + 2.0*crate::gates::U1::cost() + crate::gates::U2::cost(),
426    arg=phi, arg=lambda);
427declare_controlled!(
428    /// Controlled `U`<sub>`3`</sub> gate.
429    CU3, crate::gates::U3,
430    cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost(),
431    arg=theta, arg=phi, arg=lambda,
432    c_qasm=r#"rz {1}, {0.5 * ({lambda}-{phi})}
433cnot {0}, {1}
434rz {1}, {-0.5 * ({phi}+{lambda})}
435ry {1}, {-0.5 * {theta}}
436cnot {0}, {1}
437ry {1}, {0.5 * {theta}}
438rz {1}, {phi}
439rz {0}, {0.5 * ({phi} + {lambda})}"#);
440
441declare_controlled!(
442    /// Controlled `V` gate.
443    CV, crate::gates::V,
444    cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost());
445declare_controlled!(
446    /// Controlled `V`<sup>`†`</sup> gate.
447    CVdg, crate::gates::Vdg,
448    cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost());
449
450declare_controlled!(
451    /// Doubly controlled `R`<sub>`X`</sub> gate.
452    CCRX, crate::gates::CRX,
453    cost=2.0*CX::cost() + 3.0*CRX::cost(),
454    arg=theta,
455    open_qasm="s {2}; cx {1}, {2}; ry(-{theta}/4) {2}; cx {1}, {2}; ry({theta}/4) {2}; cx {0}, {1}; cx {1}, {2}; ry({theta}/4) {2}; cx {1}, {2}; ry(-{theta}/4) {2}; cx {0}, {1}; cx {0}, {2}; ry(-{theta}/4) {2}; cx {0}, {2}; ry({theta}/4) {2}; sdg {2}",
456    c_qasm=r#"s {2}
457cnot {1}, {2}
458ry {2}, {-0.25 * {theta}}
459cnot {1}, {2}
460ry {2}, {0.25 * {theta}}
461cnot {0}, {1}
462cnot {1}, {2}
463ry {2}, {0.25 * {theta}}
464cnot {1}, {2}
465ry {2}, {-0.25 * {theta}}
466cnot {0}, {1}
467cnot {0}, {2}
468ry {2}, {-0.25 * {theta}}
469cnot {0}, {2}
470ry {2}, {0.25 * {theta}}
471sdag {2}"#);
472declare_controlled!(
473    /// Doubly controlled `R`<sub>`Y`</sub> gate.
474    CCRY, crate::gates::CRY,
475    cost=6.0 * crate::gates::U3::cost() + 8.0*CX::cost(),
476    arg=theta,
477    open_qasm="cx {1}, {2}; u3(-{theta}/4, 0, 0) {2}; cx {1}, {2}; u3({theta}/4, 0, 0) {2}; cx {0}, {1}; cx {1}, {2}; u3({theta}/4, 0, 0) {2}; cx {1}, {2}; u3(-{theta}/4, 0, 0) {2}; cx {0}, {1}; cx {0}, {2}; u3(-{theta}/4, 0, 0) {2}; cx {0}, {2}; u3({theta}/4, 0, 0) {2}",
478    c_qasm=r#"cnot {1}, {2}
479ry {2}, {-0.25 * {theta}}
480cnot {1}, {2}
481ry {2}, {0.25 * {theta}}
482cnot {0}, {1}
483cnot {1}, {2}
484ry {2}, {0.25 * {theta}}
485cnot {1}, {2}
486ry {2}, {-0.25 * {theta}}
487cnot {0}, {1}
488cnot {0}, {2}
489ry {2}, {-0.25 * {theta}}
490cnot {0}, {2}
491ry {2}, {0.25 * {theta}}"#);
492declare_controlled!(
493    /// Doubly controlled `R`<sub>`Z`</sub> gate.
494    CCRZ, crate::gates::CRZ,
495    cost=2.0*CX::cost() + 3.0*CRZ::cost(),
496    arg=lambda,
497    open_qasm="crz({lambda}/2) {1}, {2}; cx {0}, {1}; crz(-{lambda}/2) {1}, {2}; cx {0}, {1}; crz({lambda}/2) {0}, {2}",
498    c_qasm=r#"cr {1}, {2}, {0.5 * {lambda}}
499cnot {0}, {1}
500cr {1}, {2}, {-0.5 * {lambda}}
501cnot {0}, {1}
502cr {0}, {2}, {0.5 * {lambda}}"#);
503
504declare_controlled!(
505    /// Doubly controlled `X` gate.
506    CCX, crate::gates::CX,
507    cost=6.0*CX::cost() + 7.0*crate::gates::U1::cost() + 2.0*crate::gates::U2::cost(),
508    c_qasm="toffoli {0}, {1}, {2}");
509declare_controlled!(
510    /// Doubly controlled `Z` gate.
511    CCZ, crate::gates::CZ,
512    cost=CCX::cost() + 2.0*crate::gates::H::cost(),
513    open_qasm="h {2}; ccx {0}, {1}, {2}; h {2}",
514    c_qasm="h {2}\ntoffoli {0}, {1}, {2}\nh {2}");
515
516#[cfg(test)]
517mod tests
518{
519    use crate::gates::{gate_test, Gate, H, X};
520    use crate::export::{Latex, LatexExportState, OpenQasm, CQasm};
521    use super::{C, CCRX, CCRY, CCRZ, CCX, CCZ, CH, CRX, CRY, CRZ, CS, CTdg,
522        CU1, CU3, CV};
523    use crate::cmatrix;
524
525    #[test]
526    fn test_description()
527    {
528        let gate = C::new(X::new());
529        assert_eq!(gate.description(), "CX");
530        let gate = CH::new();
531        assert_eq!(gate.description(), "CH");
532    }
533
534    #[test]
535    fn test_matrix()
536    {
537        let z = cmatrix::COMPLEX_ZERO;
538        let o = cmatrix::COMPLEX_ONE;
539        let x = cmatrix::COMPLEX_HSQRT2;
540        let i = cmatrix::COMPLEX_I;
541
542        let gate = C::new(X::new());
543        assert_complex_matrix_eq!(gate.matrix(), array![
544            [o, z, z, z],
545            [z, o, z, z],
546            [z, z, z, o],
547            [z, z, o, z]
548        ]);
549
550        let gate = C::new(H::new());
551        assert_complex_matrix_eq!(gate.matrix(), array![
552            [o, z, z,  z],
553            [z, o, z,  z],
554            [z, z, x,  x],
555            [z, z, x, -x]
556        ]);
557
558        let gate = CCRZ::new(::std::f64::consts::PI);
559        assert_complex_matrix_eq!(gate.matrix(), array![
560            [o, z, z, z, z, z,  z, z],
561            [z, o, z, z, z, z,  z, z],
562            [z, z, o, z, z, z,  z, z],
563            [z, z, z, o, z, z,  z, z],
564            [z, z, z, z, o, z,  z, z],
565            [z, z, z, z, z, o,  z, z],
566            [z, z, z, z, z, z, -i, z],
567            [z, z, z, z, z, z,  z, i]
568        ]);
569    }
570
571    #[test]
572    fn test_apply_binary()
573    {
574        let z = cmatrix::COMPLEX_ZERO;
575        let o = cmatrix::COMPLEX_ONE;
576        let x = cmatrix::COMPLEX_HSQRT2;
577        let h = o * 0.5;
578
579        let mut state = array![
580            [o, z,  h,  z],
581            [z, z, -h,  z],
582            [z, o,  h,  x],
583            [z, z, -h, -x]
584        ];
585        let result = array![
586            [o, z,  h,  z],
587            [z, z, -h,  z],
588            [z, z, -h, -x],
589            [z, o,  h,  x]
590        ];
591        gate_test(C::new(X::new()), &mut state, &result);
592
593        let mut state = array![
594            [o, z,  h,  z],
595            [z, z, -h,  z],
596            [z, o,  h,  x],
597            [z, z, -h, -x]
598        ];
599        let result = array![
600            [o, z,  h,  z],
601            [z, z, -h,  z],
602            [z, x,  z,  z],
603            [z, x,  x,  o]
604        ];
605        gate_test(CH::new(), &mut state, &result);
606    }
607
608    #[test]
609    fn test_apply_n_ary()
610    {
611        let z = cmatrix::COMPLEX_ZERO;
612        let o = cmatrix::COMPLEX_ONE;
613        let x = cmatrix::COMPLEX_HSQRT2;
614
615        let mut state = array![
616            [o,  z,  z],
617            [z,  z,  z],
618            [z,  z,  z],
619            [z,  x,  z],
620            [z,  z,  z],
621            [z,  z,  z],
622            [z,  z, -x],
623            [z, -x,  x]
624        ];
625        let result = array![
626            [o,  z,  z],
627            [z,  z,  z],
628            [z,  z,  z],
629            [z,  x,  z],
630            [z,  z,  z],
631            [z,  z,  z],
632            [z, -x,  x],
633            [z,  z, -x]
634        ];
635        gate_test(CCX::new(), &mut state, &result);
636    }
637
638    #[test]
639    fn test_cost()
640    {
641        assert_eq!(CH::new().cost(), 2550.0);
642        assert_eq!(CRX::cost(), 2411.0);
643        assert_eq!(CRY::cost(), 2404.0);
644        assert_eq!(CRZ::cost(), 2016.0);
645        assert_eq!(CCX::new().cost(), 6263.0);
646        assert_eq!(CCZ::new().cost(), 6471.0);
647        assert_eq!(CCRX::new(0.9).cost(), 9235.0);
648        assert_eq!(CCRY::new(1.6).cost(), 9214.0);
649        assert_eq!(CCRZ::new(2.12).cost(), 8050.0);
650    }
651
652    #[test]
653    fn test_open_qasm()
654    {
655        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
656        let open_qasm = CCRX::new(0.9).open_qasm(&bit_names, &[0, 1, 2]);
657        assert_eq!(open_qasm, Ok(String::from("s qb2; cx qb1, qb2; ry(-0.9/4) qb2; cx qb1, qb2; ry(0.9/4) qb2; cx qb0, qb1; cx qb1, qb2; ry(0.9/4) qb2; cx qb1, qb2; ry(-0.9/4) qb2; cx qb0, qb1; cx qb0, qb2; ry(-0.9/4) qb2; cx qb0, qb2; ry(0.9/4) qb2; sdg qb2")));
658
659        let open_qasm = CCRY::new(1.6).open_qasm(&bit_names, &[1, 2, 0]);
660        assert_eq!(open_qasm, Ok(String::from("cx qb2, qb0; u3(-1.6/4, 0, 0) qb0; cx qb2, qb0; u3(1.6/4, 0, 0) qb0; cx qb1, qb2; cx qb2, qb0; u3(1.6/4, 0, 0) qb0; cx qb2, qb0; u3(-1.6/4, 0, 0) qb0; cx qb1, qb2; cx qb1, qb0; u3(-1.6/4, 0, 0) qb0; cx qb1, qb0; u3(1.6/4, 0, 0) qb0")));
661
662        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
663        let open_qasm = CCRZ::new(2.12).open_qasm(&bit_names, &[1, 2, 0]);
664        assert_eq!(open_qasm, Ok(String::from("crz(2.12/2) qb2, qb0; cx qb1, qb2; crz(-2.12/2) qb2, qb0; cx qb1, qb2; crz(2.12/2) qb1, qb0")));
665
666        let bit_names = [String::from("qb0"), String::from("qb1")];
667        let open_qasm = CRX::new(0.9).open_qasm(&bit_names, &[0, 1]);
668        assert_eq!(open_qasm, Ok(String::from("s qb1; cx qb0, qb1; ry(-0.9/2) qb1; cx qb0, qb1; ry(0.9/2) qb1; sdg qb1")));
669
670        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
671        let open_qasm = CCZ::new().open_qasm(&bit_names, &[0, 1, 2]);
672        assert_eq!(open_qasm, Ok(String::from("h qb2; ccx qb0, qb1, qb2; h qb2")));
673
674        let bit_names = [String::from("qb0"), String::from("qb1")];
675        let qasm = CS::new().open_qasm(&bit_names, &[0, 1]);
676        assert_eq!(qasm, Ok(String::from("cu1(pi/2) qb0, qb1")));
677
678        let bit_names = [String::from("qb0"), String::from("qb1")];
679        let qasm = CTdg::new().open_qasm(&bit_names, &[0, 1]);
680        assert_eq!(qasm, Ok(String::from("cu1(-pi/4) qb0, qb1")));
681
682        let bit_names = [String::from("qb0"), String::from("qb1")];
683        let qasm = CU1::new(1.2345678).open_qasm(&bit_names, &[0, 1]);
684        assert_eq!(qasm, Ok(String::from("cu1(1.2345678) qb0, qb1")));
685
686        let bit_names = [String::from("qb0"), String::from("qb1")];
687        let qasm = CU3::new(1.2345678, 3.1415, -0.9876).open_qasm(&bit_names, &[0, 1]);
688        assert_eq!(qasm, Ok(String::from("cu3(1.2345678, 3.1415, -0.9876) qb0, qb1")));
689    }
690
691    #[test]
692    fn test_c_qasm()
693    {
694        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
695        let c_qasm = CCRX::new(0.9).c_qasm(&bit_names, &[0, 1, 2]);
696        assert_eq!(c_qasm, Ok(String::from(
697r#"s qb2
698cnot qb1, qb2
699ry qb2, -0.225
700cnot qb1, qb2
701ry qb2, 0.225
702cnot qb0, qb1
703cnot qb1, qb2
704ry qb2, 0.225
705cnot qb1, qb2
706ry qb2, -0.225
707cnot qb0, qb1
708cnot qb0, qb2
709ry qb2, -0.225
710cnot qb0, qb2
711ry qb2, 0.225
712sdag qb2"#)));
713
714        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
715        let c_qasm = CCRY::new(1.6).c_qasm(&bit_names, &[1, 2, 0]);
716        assert_eq!(c_qasm, Ok(String::from(
717r#"cnot qb2, qb0
718ry qb0, -0.4
719cnot qb2, qb0
720ry qb0, 0.4
721cnot qb1, qb2
722cnot qb2, qb0
723ry qb0, 0.4
724cnot qb2, qb0
725ry qb0, -0.4
726cnot qb1, qb2
727cnot qb1, qb0
728ry qb0, -0.4
729cnot qb1, qb0
730ry qb0, 0.4"#)));
731
732        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
733        let c_qasm = CCRZ::new(2.12).c_qasm(&bit_names, &[1, 2, 0]);
734        assert_eq!(c_qasm, Ok(String::from(
735r#"cr qb2, qb0, 1.06
736cnot qb1, qb2
737cr qb2, qb0, -1.06
738cnot qb1, qb2
739cr qb1, qb0, 1.06"#)));
740
741        let bit_names = [String::from("qb0"), String::from("qb1"), String::from("qb2")];
742        let c_qasm = CCZ::new().c_qasm(&bit_names, &[0, 1, 2]);
743        assert_eq!(c_qasm, Ok(String::from("h qb2\ntoffoli qb0, qb1, qb2\nh qb2")));
744
745        let bit_names = [String::from("qb0"), String::from("qb1")];
746        let c_qasm = CRX::new(0.9).c_qasm(&bit_names, &[0, 1]);
747        assert_eq!(c_qasm, Ok(String::from(
748r#"s qb1
749cnot qb0, qb1
750ry qb1, -0.45
751cnot qb0, qb1
752ry qb1, 0.45
753sdag qb1"#)));
754
755        let bit_names = [String::from("qb0"), String::from("qb1")];
756        let qasm = CS::new().c_qasm(&bit_names, &[0, 1]);
757        assert_eq!(qasm, Ok(String::from("crk qb0, qb1, 1")));
758
759        let bit_names = [String::from("qb0"), String::from("qb1")];
760        let qasm = CTdg::new().c_qasm(&bit_names, &[0, 1]);
761        assert_eq!(qasm, Ok(String::from("cr qb0, qb1, -0.7853981633974483")));
762
763        let bit_names = [String::from("qb0"), String::from("qb1")];
764        let qasm = CU1::new(1.2345678).c_qasm(&bit_names, &[0, 1]);
765        assert_eq!(qasm, Ok(String::from("cr qb0, qb1, 1.2345678")));
766
767        let bit_names = [String::from("qb0"), String::from("qb1")];
768        let qasm = CU3::new(1.2345678, 3.1415, -0.9876).c_qasm(&bit_names, &[0, 1]);
769        assert_eq!(qasm, Ok(String::from(
770r#"rz qb1, -2.06455
771cnot qb0, qb1
772rz qb1, -1.07695
773ry qb1, -0.6172839
774cnot qb0, qb1
775ry qb1, 0.6172839
776rz qb1, 3.1415
777rz qb0, 1.07695"#)));
778    }
779
780    #[test]
781    fn test_latex()
782    {
783        let gate = CS::new();
784        let mut state = LatexExportState::new(2, 0);
785        assert_eq!(gate.latex(&[0, 1], &mut state), Ok(()));
786        assert_eq!(state.code(),
787r#"\Qcircuit @C=1em @R=.7em {
788    \lstick{\ket{0}} & \ctrl{1} & \qw \\
789    \lstick{\ket{0}} & \gate{S} & \qw \\
790}
791"#);
792
793        let gate = CV::new();
794        let mut state = LatexExportState::new(2, 0);
795        assert_eq!(gate.latex(&[1, 0], &mut state), Ok(()));
796        assert_eq!(state.code(),
797r#"\Qcircuit @C=1em @R=.7em {
798    \lstick{\ket{0}} & \gate{V} & \qw \\
799    \lstick{\ket{0}} & \ctrl{-1} & \qw \\
800}
801"#);
802
803        let gate = CCRX::new(-0.26);
804        let mut state = LatexExportState::new(3, 0);
805        assert_eq!(gate.latex(&[2, 1, 0], &mut state), Ok(()));
806        assert_eq!(state.code(),
807r#"\Qcircuit @C=1em @R=.7em {
808    \lstick{\ket{0}} & \gate{R_x(-0.2600)} & \qw \\
809    \lstick{\ket{0}} & \ctrl{-1} & \qw \\
810    \lstick{\ket{0}} & \ctrl{-1} & \qw \\
811}
812"#);
813    }
814
815    #[test]
816    #[should_panic]
817    fn test_latex_error()
818    {
819        let gate = CCX::new();
820        let mut state = LatexExportState::new(3, 0);
821        let _ltx = gate.latex(&[1, 2, 0], &mut state);
822    }
823}