quantrs2_core/optimization/
mod.rs1pub mod compression;
7pub mod fusion;
8pub mod lazy_evaluation;
9pub mod peephole;
10pub mod zx_optimizer;
11
12use crate::error::QuantRS2Result;
13use crate::gate::GateOp;
14use crate::qubit::QubitId;
15
16pub trait OptimizationPass {
18 fn optimize(&self, gates: Vec<Box<dyn GateOp>>) -> QuantRS2Result<Vec<Box<dyn GateOp>>>;
20
21 fn name(&self) -> &str;
23
24 fn is_applicable(&self, gates: &[Box<dyn GateOp>]) -> bool {
26 !gates.is_empty()
27 }
28}
29
30pub struct OptimizationChain {
32 passes: Vec<Box<dyn OptimizationPass>>,
33}
34
35impl OptimizationChain {
36 pub fn new() -> Self {
38 Self { passes: Vec::new() }
39 }
40
41 #[must_use]
43 pub fn add_pass(mut self, pass: Box<dyn OptimizationPass>) -> Self {
44 self.passes.push(pass);
45 self
46 }
47
48 pub fn optimize(
50 &self,
51 mut gates: Vec<Box<dyn GateOp>>,
52 ) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
53 for pass in &self.passes {
54 if pass.is_applicable(&gates) {
55 gates = pass.optimize(gates)?;
56 }
57 }
58 Ok(gates)
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct GateInfo {
65 pub gate: Box<dyn GateOp>,
67 pub index: usize,
69 pub qubits: Vec<QubitId>,
71 pub is_parameterized: bool,
73}
74
75pub fn gates_are_disjoint(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
77 let qubits1 = gate1.qubits();
78 let qubits2 = gate2.qubits();
79
80 for q1 in &qubits1 {
81 for q2 in &qubits2 {
82 if q1 == q2 {
83 return false;
84 }
85 }
86 }
87 true
88}
89
90pub fn gates_can_commute(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
92 if gates_are_disjoint(gate1, gate2) {
94 return true;
95 }
96
97 if gate1.qubits().len() == 1 && gate2.qubits().len() == 1 && gate1.qubits() == gate2.qubits() {
99 match (gate1.name(), gate2.name()) {
100 ("Z" | "S" | "S†" | "T" | "T†" | "RZ", "Z" | "S" | "T")
102 | ("Z" | "S" | "S†" | "T" | "T†", "S†" | "T†")
103 | ("RZ", "RZ")
104 | ("X" | "RX", "X" | "RX") | ("Y" | "RY", "Y" | "RY") => true, _ => false,
108 }
109 } else {
110 false
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::gate::single::{Hadamard, PauliX, PauliZ};
118 use crate::qubit::QubitId;
119
120 #[test]
121 fn test_gates_are_disjoint() {
122 let gate1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
123 let gate2 = Box::new(PauliZ { target: QubitId(1) }) as Box<dyn GateOp>;
124 let gate3 = Box::new(Hadamard { target: QubitId(0) }) as Box<dyn GateOp>;
125
126 assert!(gates_are_disjoint(gate1.as_ref(), gate2.as_ref()));
127 assert!(!gates_are_disjoint(gate1.as_ref(), gate3.as_ref()));
128 }
129
130 #[test]
131 fn test_gates_can_commute() {
132 let z1 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
133 let z2 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
134 let x1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
135
136 assert!(gates_can_commute(z1.as_ref(), z2.as_ref()));
137 assert!(!gates_can_commute(z1.as_ref(), x1.as_ref()));
138 }
139}