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