1use crate::error::QuantRS2Result;
2use crate::gate::{multi, single, GateOp};
3use crate::qubit::QubitId;
4use num_complex::Complex64;
5use std::any::Any;
6use std::f64::consts::PI;
7
8pub mod clifford_t;
9pub mod solovay_kitaev;
10
11pub trait GateDecomposable: GateOp {
13 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>>;
15
16 fn is_decomposable(&self) -> bool {
18 true
19 }
20}
21
22pub trait GateComposable: GateOp {
24 fn compose_with(&self, other: &dyn GateOp) -> QuantRS2Result<Box<dyn GateOp>>;
26
27 fn can_compose_with(&self, other: &dyn GateOp) -> bool;
29}
30
31pub fn decompose_swap(qubit1: QubitId, qubit2: QubitId) -> Vec<Box<dyn GateOp>> {
33 vec![
34 Box::new(multi::CNOT {
35 control: qubit1,
36 target: qubit2,
37 }),
38 Box::new(multi::CNOT {
39 control: qubit2,
40 target: qubit1,
41 }),
42 Box::new(multi::CNOT {
43 control: qubit1,
44 target: qubit2,
45 }),
46 ]
47}
48
49pub fn decompose_toffoli(
51 control1: QubitId,
52 control2: QubitId,
53 target: QubitId,
54) -> Vec<Box<dyn GateOp>> {
55 vec![
56 Box::new(single::RotationY {
57 target,
58 theta: PI / 4.0,
59 }),
60 Box::new(multi::CNOT {
61 control: control2,
62 target,
63 }),
64 Box::new(single::RotationY {
65 target,
66 theta: -PI / 4.0,
67 }),
68 Box::new(multi::CNOT {
69 control: control1,
70 target,
71 }),
72 Box::new(single::RotationY {
73 target,
74 theta: PI / 4.0,
75 }),
76 Box::new(multi::CNOT {
77 control: control2,
78 target,
79 }),
80 Box::new(single::RotationY {
81 target,
82 theta: -PI / 4.0,
83 }),
84 Box::new(multi::CNOT {
85 control: control1,
86 target: control2,
87 }),
88 Box::new(single::RotationY {
89 target: control2,
90 theta: PI / 4.0,
91 }),
92 Box::new(multi::CNOT {
93 control: control1,
94 target: control2,
95 }),
96 Box::new(single::RotationY {
97 target: control2,
98 theta: -PI / 4.0,
99 }),
100 Box::new(single::Hadamard { target: control1 }),
101 Box::new(single::Hadamard { target: control2 }),
102 Box::new(single::Hadamard { target }),
103 Box::new(single::RotationX {
104 target: control1,
105 theta: PI / 4.0,
106 }),
107 Box::new(single::RotationX {
108 target: control2,
109 theta: PI / 4.0,
110 }),
111 Box::new(single::RotationX {
112 target,
113 theta: PI / 4.0,
114 }),
115 ]
116}
117
118pub fn decompose_fredkin(
120 control: QubitId,
121 target1: QubitId,
122 target2: QubitId,
123) -> Vec<Box<dyn GateOp>> {
124 let mut gates: Vec<Box<dyn GateOp>> = Vec::new();
126
127 gates.push(Box::new(multi::CNOT {
133 control: target2,
134 target: target1,
135 }));
136
137 let toffoli_gates = decompose_toffoli(control, target1, target2);
139 gates.extend(toffoli_gates);
140
141 gates.push(Box::new(multi::CNOT {
142 control: target2,
143 target: target1,
144 }));
145
146 gates
147}
148
149pub fn decompose_controlled_rotation(
151 control: QubitId,
152 target: QubitId,
153 gate_type: &str,
154 theta: f64,
155) -> Vec<Box<dyn GateOp>> {
156 let mut gates: Vec<Box<dyn GateOp>> = Vec::new();
157
158 match gate_type {
159 "RX" => {
160 gates.push(Box::new(single::RotationZ {
168 target,
169 theta: PI / 2.0,
170 }));
171 gates.push(Box::new(multi::CNOT { control, target }));
172 gates.push(Box::new(single::RotationY {
173 target,
174 theta: -theta / 2.0,
175 }));
176 gates.push(Box::new(multi::CNOT { control, target }));
177 gates.push(Box::new(single::RotationY {
178 target,
179 theta: theta / 2.0,
180 }));
181 gates.push(Box::new(single::RotationZ {
182 target,
183 theta: -PI / 2.0,
184 }));
185 }
186 "RY" => {
187 gates.push(Box::new(multi::CNOT { control, target }));
193 gates.push(Box::new(single::RotationY {
194 target,
195 theta: -theta / 2.0,
196 }));
197 gates.push(Box::new(multi::CNOT { control, target }));
198 gates.push(Box::new(single::RotationY {
199 target,
200 theta: theta / 2.0,
201 }));
202 }
203 "RZ" => {
204 gates.push(Box::new(single::RotationZ {
210 target,
211 theta: theta / 2.0,
212 }));
213 gates.push(Box::new(multi::CNOT { control, target }));
214 gates.push(Box::new(single::RotationZ {
215 target,
216 theta: -theta / 2.0,
217 }));
218 gates.push(Box::new(multi::CNOT { control, target }));
219 }
220 _ => {
221 }
223 }
224
225 gates
226}
227
228pub fn decompose_u_gate(
230 target: QubitId,
231 theta: f64,
232 phi: f64,
233 lambda: f64,
234) -> Vec<Box<dyn GateOp>> {
235 vec![
236 Box::new(single::RotationZ {
237 target,
238 theta: lambda,
239 }),
240 Box::new(single::RotationY { target, theta }),
241 Box::new(single::RotationZ { target, theta: phi }),
242 ]
243}
244
245#[derive(Debug)]
247pub struct CompositeGate {
248 pub gates: Vec<Box<dyn GateOp>>,
250
251 pub qubits: Vec<QubitId>,
253
254 pub name: String,
256}
257
258impl GateOp for CompositeGate {
259 fn name(&self) -> &'static str {
260 "Composite" }
262
263 fn qubits(&self) -> Vec<QubitId> {
264 self.qubits.clone()
265 }
266
267 fn is_parameterized(&self) -> bool {
268 self.gates.iter().any(|g| g.is_parameterized())
270 }
271
272 fn matrix(&self) -> QuantRS2Result<Vec<Complex64>> {
273 Err(crate::error::QuantRS2Error::UnsupportedOperation(
274 "Direct matrix representation of composite gates not supported. \
275 Use gate decomposition."
276 .into(),
277 ))
278 }
279
280 fn as_any(&self) -> &dyn Any {
281 self
282 }
283
284 fn clone_gate(&self) -> Box<dyn GateOp> {
285 Box::new(CompositeGate {
286 gates: self.gates.iter().map(|g| g.clone()).collect(),
287 qubits: self.qubits.clone(),
288 name: self.name.clone(),
289 })
290 }
291}
292
293impl GateDecomposable for CompositeGate {
294 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
295 let mut result: Vec<Box<dyn GateOp>> = Vec::with_capacity(self.gates.len());
297 for gate in &self.gates {
298 if let Some(h) = gate.as_any().downcast_ref::<single::Hadamard>() {
301 result.push(Box::new(single::Hadamard { target: h.target }) as Box<dyn GateOp>);
302 } else if let Some(x) = gate.as_any().downcast_ref::<single::PauliX>() {
303 result.push(Box::new(single::PauliX { target: x.target }) as Box<dyn GateOp>);
304 } else if let Some(y) = gate.as_any().downcast_ref::<single::PauliY>() {
305 result.push(Box::new(single::PauliY { target: y.target }) as Box<dyn GateOp>);
306 } else if let Some(z) = gate.as_any().downcast_ref::<single::PauliZ>() {
307 result.push(Box::new(single::PauliZ { target: z.target }) as Box<dyn GateOp>);
308 } else if let Some(cnot) = gate.as_any().downcast_ref::<multi::CNOT>() {
309 result.push(Box::new(multi::CNOT {
310 control: cnot.control,
311 target: cnot.target,
312 }) as Box<dyn GateOp>);
313 } else {
314 return Err(crate::error::QuantRS2Error::UnsupportedOperation(format!(
317 "Gate type {} not supported for decomposition cloning",
318 gate.name()
319 )));
320 }
321 }
322 Ok(result)
323 }
324
325 fn is_decomposable(&self) -> bool {
326 true
327 }
328}
329
330impl GateDecomposable for multi::Toffoli {
332 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
333 Ok(decompose_toffoli(self.control1, self.control2, self.target))
334 }
335}
336
337impl GateDecomposable for multi::Fredkin {
339 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
340 Ok(decompose_fredkin(self.control, self.target1, self.target2))
341 }
342}
343
344impl GateDecomposable for multi::SWAP {
346 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
347 Ok(decompose_swap(self.qubit1, self.qubit2))
348 }
349}
350
351impl GateDecomposable for multi::CRX {
353 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
354 Ok(decompose_controlled_rotation(
355 self.control,
356 self.target,
357 "RX",
358 self.theta,
359 ))
360 }
361}
362
363impl GateDecomposable for multi::CRY {
365 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
366 Ok(decompose_controlled_rotation(
367 self.control,
368 self.target,
369 "RY",
370 self.theta,
371 ))
372 }
373}
374
375impl GateDecomposable for multi::CRZ {
377 fn decompose(&self) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
378 Ok(decompose_controlled_rotation(
379 self.control,
380 self.target,
381 "RZ",
382 self.theta,
383 ))
384 }
385}
386
387pub mod utils {
389 use super::*;
390
391 pub type GateSequence = Vec<Box<dyn GateOp>>;
393
394 pub fn clone_gate(gate: &dyn GateOp) -> QuantRS2Result<Box<dyn GateOp>> {
396 if let Some(h) = gate.as_any().downcast_ref::<single::Hadamard>() {
397 Ok(Box::new(single::Hadamard { target: h.target }))
398 } else if let Some(x) = gate.as_any().downcast_ref::<single::PauliX>() {
399 Ok(Box::new(single::PauliX { target: x.target }))
400 } else if let Some(y) = gate.as_any().downcast_ref::<single::PauliY>() {
401 Ok(Box::new(single::PauliY { target: y.target }))
402 } else if let Some(z) = gate.as_any().downcast_ref::<single::PauliZ>() {
403 Ok(Box::new(single::PauliZ { target: z.target }))
404 } else if let Some(cnot) = gate.as_any().downcast_ref::<multi::CNOT>() {
405 Ok(Box::new(multi::CNOT {
406 control: cnot.control,
407 target: cnot.target,
408 }))
409 } else if let Some(rx) = gate.as_any().downcast_ref::<single::RotationX>() {
410 Ok(Box::new(single::RotationX {
411 target: rx.target,
412 theta: rx.theta,
413 }))
414 } else if let Some(ry) = gate.as_any().downcast_ref::<single::RotationY>() {
415 Ok(Box::new(single::RotationY {
416 target: ry.target,
417 theta: ry.theta,
418 }))
419 } else if let Some(rz) = gate.as_any().downcast_ref::<single::RotationZ>() {
420 Ok(Box::new(single::RotationZ {
421 target: rz.target,
422 theta: rz.theta,
423 }))
424 } else if let Some(s) = gate.as_any().downcast_ref::<single::Phase>() {
425 Ok(Box::new(single::Phase { target: s.target }))
426 } else if let Some(t) = gate.as_any().downcast_ref::<single::T>() {
427 Ok(Box::new(single::T { target: t.target }))
428 } else if let Some(swap) = gate.as_any().downcast_ref::<multi::SWAP>() {
429 Ok(Box::new(multi::SWAP {
430 qubit1: swap.qubit1,
431 qubit2: swap.qubit2,
432 }))
433 } else {
434 Err(crate::error::QuantRS2Error::UnsupportedOperation(format!(
436 "Gate type {} not supported for cloning",
437 gate.name()
438 )))
439 }
440 }
441
442 pub fn optimize_gate_sequence(gates: &[Box<dyn GateOp>]) -> QuantRS2Result<GateSequence> {
444 let mut result: Vec<Box<dyn GateOp>> = Vec::new();
445 let mut i = 0;
446
447 while i < gates.len() {
448 if i + 1 < gates.len() {
450 let gate1 = &gates[i];
451 let gate2 = &gates[i + 1];
452
453 if try_cancel_gates(gate1.as_ref(), gate2.as_ref()).is_some() {
454 i += 2;
456 continue;
457 }
458
459 if let Some(composed) = try_compose_gates(gate1.as_ref(), gate2.as_ref()) {
460 result.push(composed);
462 i += 2;
463 continue;
464 }
465 }
466
467 let gate = &gates[i];
470 if let Some(h) = gate.as_any().downcast_ref::<single::Hadamard>() {
471 result.push(Box::new(single::Hadamard { target: h.target }) as Box<dyn GateOp>);
472 } else if let Some(x) = gate.as_any().downcast_ref::<single::PauliX>() {
473 result.push(Box::new(single::PauliX { target: x.target }) as Box<dyn GateOp>);
474 } else if let Some(y) = gate.as_any().downcast_ref::<single::PauliY>() {
475 result.push(Box::new(single::PauliY { target: y.target }) as Box<dyn GateOp>);
476 } else if let Some(z) = gate.as_any().downcast_ref::<single::PauliZ>() {
477 result.push(Box::new(single::PauliZ { target: z.target }) as Box<dyn GateOp>);
478 } else if let Some(cnot) = gate.as_any().downcast_ref::<multi::CNOT>() {
479 result.push(Box::new(multi::CNOT {
480 control: cnot.control,
481 target: cnot.target,
482 }) as Box<dyn GateOp>);
483 } else {
484 return Err(crate::error::QuantRS2Error::UnsupportedOperation(format!(
486 "Gate type {} not supported for optimization cloning",
487 gate.name()
488 )));
489 }
490 i += 1;
491 }
492
493 Ok(result)
494 }
495
496 fn try_cancel_gates(gate1: &dyn GateOp, gate2: &dyn GateOp) -> Option<()> {
498 if gate1.name() == gate2.name() && gate1.qubits() == gate2.qubits() {
500 match gate1.name() {
501 "H" | "X" | "Y" | "Z" | "SWAP" => {
503 return Some(());
504 }
505 "S" => {
507 if gate2.name() == "S†" {
508 return Some(());
509 }
510 }
511 "S†" => {
512 if gate2.name() == "S" {
513 return Some(());
514 }
515 }
516 "T" => {
517 if gate2.name() == "T†" {
518 return Some(());
519 }
520 }
521 "T†" => {
522 if gate2.name() == "T" {
523 return Some(());
524 }
525 }
526 "RX" | "RY" | "RZ" => {
528 }
530 _ => {}
531 }
532 }
533
534 None
535 }
536
537 fn try_compose_gates(gate1: &dyn GateOp, gate2: &dyn GateOp) -> Option<Box<dyn GateOp>> {
539 if gate1.qubits() == gate2.qubits() {
541 match (gate1.name(), gate2.name()) {
542 ("RX", "RX") => {
544 if let (Some(rx1), Some(rx2)) = (
545 gate1.as_any().downcast_ref::<single::RotationX>(),
546 gate2.as_any().downcast_ref::<single::RotationX>(),
547 ) {
548 return Some(Box::new(single::RotationX {
549 target: rx1.target,
550 theta: rx1.theta + rx2.theta,
551 }));
552 }
553 }
554 ("RY", "RY") => {
555 if let (Some(ry1), Some(ry2)) = (
556 gate1.as_any().downcast_ref::<single::RotationY>(),
557 gate2.as_any().downcast_ref::<single::RotationY>(),
558 ) {
559 return Some(Box::new(single::RotationY {
560 target: ry1.target,
561 theta: ry1.theta + ry2.theta,
562 }));
563 }
564 }
565 ("RZ", "RZ") => {
566 if let (Some(rz1), Some(rz2)) = (
567 gate1.as_any().downcast_ref::<single::RotationZ>(),
568 gate2.as_any().downcast_ref::<single::RotationZ>(),
569 ) {
570 return Some(Box::new(single::RotationZ {
571 target: rz1.target,
572 theta: rz1.theta + rz2.theta,
573 }));
574 }
575 }
576 _ => {}
578 }
579 }
580
581 None
582 }
583
584 pub fn decompose_circuit(gates: &[Box<dyn GateOp>]) -> QuantRS2Result<GateSequence> {
586 let mut result: Vec<Box<dyn GateOp>> = Vec::new();
587
588 for gate in gates {
589 if let Some(toff) = gate.as_any().downcast_ref::<multi::Toffoli>() {
591 let decomposed = decompose_toffoli(toff.control1, toff.control2, toff.target);
593 let fully_decomposed = decompose_circuit(&decomposed)?;
595 result.extend(fully_decomposed);
596 } else if let Some(fred) = gate.as_any().downcast_ref::<multi::Fredkin>() {
597 let decomposed = decompose_fredkin(fred.control, fred.target1, fred.target2);
599 let fully_decomposed = decompose_circuit(&decomposed)?;
601 result.extend(fully_decomposed);
602 } else if let Some(swap) = gate.as_any().downcast_ref::<multi::SWAP>() {
603 let decomposed = decompose_swap(swap.qubit1, swap.qubit2);
605 let fully_decomposed = decompose_circuit(&decomposed)?;
607 result.extend(fully_decomposed);
608 } else if let Some(crx) = gate.as_any().downcast_ref::<multi::CRX>() {
609 let decomposed =
611 decompose_controlled_rotation(crx.control, crx.target, "RX", crx.theta);
612 let fully_decomposed = decompose_circuit(&decomposed)?;
614 result.extend(fully_decomposed);
615 } else if let Some(h) = gate.as_any().downcast_ref::<single::Hadamard>() {
616 result.push(Box::new(single::Hadamard { target: h.target }) as Box<dyn GateOp>);
618 } else if let Some(x) = gate.as_any().downcast_ref::<single::PauliX>() {
619 result.push(Box::new(single::PauliX { target: x.target }) as Box<dyn GateOp>);
620 } else if let Some(cnot) = gate.as_any().downcast_ref::<multi::CNOT>() {
621 result.push(Box::new(multi::CNOT {
622 control: cnot.control,
623 target: cnot.target,
624 }) as Box<dyn GateOp>);
625 } else {
626 return Err(crate::error::QuantRS2Error::UnsupportedOperation(format!(
628 "Gate type {} not supported for decomposition",
629 gate.name()
630 )));
631 }
632 }
633
634 Ok(result)
635 }
636}