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 pub fn add_pass(mut self, pass: Box<dyn OptimizationPass>) -> Self {
43 self.passes.push(pass);
44 self
45 }
46
47 pub fn optimize(
49 &self,
50 mut gates: Vec<Box<dyn GateOp>>,
51 ) -> QuantRS2Result<Vec<Box<dyn GateOp>>> {
52 for pass in &self.passes {
53 if pass.is_applicable(&gates) {
54 gates = pass.optimize(gates)?;
55 }
56 }
57 Ok(gates)
58 }
59}
60
61#[derive(Debug, Clone)]
63pub struct GateInfo {
64 pub gate: Box<dyn GateOp>,
66 pub index: usize,
68 pub qubits: Vec<QubitId>,
70 pub is_parameterized: bool,
72}
73
74pub fn gates_are_disjoint(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
76 let qubits1 = gate1.qubits();
77 let qubits2 = gate2.qubits();
78
79 for q1 in &qubits1 {
80 for q2 in &qubits2 {
81 if q1 == q2 {
82 return false;
83 }
84 }
85 }
86 true
87}
88
89pub fn gates_can_commute(gate1: &dyn GateOp, gate2: &dyn GateOp) -> bool {
91 if gates_are_disjoint(gate1, gate2) {
93 return true;
94 }
95
96 if gate1.qubits().len() == 1 && gate2.qubits().len() == 1 && gate1.qubits() == gate2.qubits() {
98 match (gate1.name(), gate2.name()) {
99 ("Z", "Z")
101 | ("Z", "S")
102 | ("Z", "S†")
103 | ("Z", "T")
104 | ("Z", "T†")
105 | ("S", "Z")
106 | ("S", "S")
107 | ("S", "S†")
108 | ("S", "T")
109 | ("S", "T†")
110 | ("S†", "Z")
111 | ("S†", "S")
112 | ("S†", "S†")
113 | ("S†", "T")
114 | ("S†", "T†")
115 | ("T", "Z")
116 | ("T", "S")
117 | ("T", "S†")
118 | ("T", "T")
119 | ("T", "T†")
120 | ("T†", "Z")
121 | ("T†", "S")
122 | ("T†", "S†")
123 | ("T†", "T")
124 | ("T†", "T†")
125 | ("RZ", "RZ")
126 | ("RZ", "Z")
127 | ("RZ", "S")
128 | ("RZ", "T") => true,
129
130 ("X", "X") | ("RX", "RX") | ("RX", "X") | ("X", "RX") => true,
132
133 ("Y", "Y") | ("RY", "RY") | ("RY", "Y") | ("Y", "RY") => true,
135
136 _ => false,
137 }
138 } else {
139 false
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::gate::single::{Hadamard, PauliX, PauliZ};
147 use crate::qubit::QubitId;
148
149 #[test]
150 fn test_gates_are_disjoint() {
151 let gate1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
152 let gate2 = Box::new(PauliZ { target: QubitId(1) }) as Box<dyn GateOp>;
153 let gate3 = Box::new(Hadamard { target: QubitId(0) }) as Box<dyn GateOp>;
154
155 assert!(gates_are_disjoint(gate1.as_ref(), gate2.as_ref()));
156 assert!(!gates_are_disjoint(gate1.as_ref(), gate3.as_ref()));
157 }
158
159 #[test]
160 fn test_gates_can_commute() {
161 let z1 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
162 let z2 = Box::new(PauliZ { target: QubitId(0) }) as Box<dyn GateOp>;
163 let x1 = Box::new(PauliX { target: QubitId(0) }) as Box<dyn GateOp>;
164
165 assert!(gates_can_commute(z1.as_ref(), z2.as_ref()));
166 assert!(!gates_can_commute(z1.as_ref(), x1.as_ref()));
167 }
168}