1use crate::gates::{Gate, CX};
16
17pub 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 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 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 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 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#[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 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 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 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 CRZ, crate::gates::RZ,
391 cost=2.0*CX::cost() + 2.0*crate::gates::U1::cost(),
392 arg=lambda);
393
394declare_controlled!(
395 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 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 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 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 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 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 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 CV, crate::gates::V,
444 cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost());
445declare_controlled!(
446 CVdg, crate::gates::Vdg,
448 cost=2.0*CX::cost() + crate::gates::U1::cost() + 2.0*crate::gates::U3::cost());
449
450declare_controlled!(
451 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 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 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 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 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}