quantrs2_core/optimization/
mod.rs1pub mod compression;
7pub mod fusion;
8pub mod peephole;
9pub mod zx_optimizer;
10
11use crate::error::QuantRS2Result;
12use crate::gate::GateOp;
13use crate::qubit::QubitId;
14
15pub trait OptimizationPass {
17 fn optimize(&self, gates: Vec<Box<dyn GateOp>>) -> QuantRS2Result<Vec<Box<dyn GateOp>>>;
19
20 fn name(&self) -> &str;
22
23 fn is_applicable(&self, gates: &[Box<dyn GateOp>]) -> bool {
25 !gates.is_empty()
26 }
27}
28
29pub struct OptimizationChain {
31 passes: Vec<Box<dyn OptimizationPass>>,
32}
33
34impl OptimizationChain {
35 pub fn new() -> Self {
37 Self { passes: Vec::new() }
38 }
39
40 pub fn add_pass(mut self, pass: Box<dyn OptimizationPass>) -> Self {
42 self.passes.push(pass);
43 self
44 }
45
46 pub fn optimize(
48 &self,
49 mut gates: Vec<Box<dyn GateOp>>,
50 ) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
51 for pass in &self.passes {
52 if pass.is_applicable(&gates) {
53 gates = pass.optimize(gates)?;
54 }
55 }
56 Ok(gates)
57 }
58}
59
60#[derive(Debug, Clone)]
62pub struct GateInfo {
63 pub gate: Box<dyn GateOp>,
65 pub index: usize,
67 pub qubits: Vec<QubitId>,
69 pub is_parameterized: bool,
71}
72
73pub fn gates_are_disjoint(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
75 let qubits1 = gate1.qubits();
76 let qubits2 = gate2.qubits();
77
78 for q1 in &qubits1 {
79 for q2 in &qubits2 {
80 if q1 == q2 {
81 return false;
82 }
83 }
84 }
85 true
86}
87
88pub fn gates_can_commute(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
90 if gates_are_disjoint(gate1, gate2) {
92 return true;
93 }
94
95 if gate1.qubits().len() == 1 && gate2.qubits().len() == 1 && gate1.qubits() == gate2.qubits() {
97 match (gate1.name(), gate2.name()) {
98 ("Z", "Z")
100 | ("Z", "S")
101 | ("Z", "S†")
102 | ("Z", "T")
103 | ("Z", "T†")
104 | ("S", "Z")
105 | ("S", "S")
106 | ("S", "S†")
107 | ("S", "T")
108 | ("S", "T†")
109 | ("S†", "Z")
110 | ("S†", "S")
111 | ("S†", "S†")
112 | ("S†", "T")
113 | ("S†", "T†")
114 | ("T", "Z")
115 | ("T", "S")
116 | ("T", "S†")
117 | ("T", "T")
118 | ("T", "T†")
119 | ("T†", "Z")
120 | ("T†", "S")
121 | ("T†", "S†")
122 | ("T†", "T")
123 | ("T†", "T†")
124 | ("RZ", "RZ")
125 | ("RZ", "Z")
126 | ("RZ", "S")
127 | ("RZ", "T") => true,
128
129 ("X", "X") | ("RX", "RX") | ("RX", "X") | ("X", "RX") => true,
131
132 ("Y", "Y") | ("RY", "RY") | ("RY", "Y") | ("Y", "RY") => true,
134
135 _ => false,
136 }
137 } else {
138 false
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::gate::single::{Hadamard, PauliX, PauliZ};
146 use crate::qubit::QubitId;
147
148 #[test]
149 fn test_gates_are_disjoint() {
150 let gate1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
151 let gate2 = Box::new(PauliZ { target: QubitId(1) }) as Box<dyn GateOp>;
152 let gate3 = Box::new(Hadamard { target: QubitId(0) }) as Box<dyn GateOp>;
153
154 assert!(gates_are_disjoint(gate1.as_ref(), gate2.as_ref()));
155 assert!(!gates_are_disjoint(gate1.as_ref(), gate3.as_ref()));
156 }
157
158 #[test]
159 fn test_gates_can_commute() {
160 let z1 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
161 let z2 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
162 let x1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
163
164 assert!(gates_can_commute(z1.as_ref(), z2.as_ref()));
165 assert!(!gates_can_commute(z1.as_ref(), x1.as_ref()));
166 }
167}