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