quantrs2_circuit/optimization/
pass_manager.rs

1//! Pass manager for orchestrating optimization passes
2//!
3//! This module manages the execution of optimization passes in a configurable way.
4
5use crate::builder::Circuit;
6use crate::optimization::cost_model::{CircuitCostExt, CostModel};
7use crate::optimization::passes::{
8    CircuitRewriting, CostBasedOptimization, CostTarget, DecompositionOptimization,
9    GateCancellation, GateCommutation, GateMerging, OptimizationPass, OptimizationPassExt,
10    PeepholeOptimization, RotationMerging, TemplateMatching, TwoQubitOptimization,
11};
12use quantrs2_core::error::QuantRS2Result;
13use serde::{Deserialize, Serialize};
14use std::collections::HashSet;
15
16/// Optimization level presets
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18pub enum OptimizationLevel {
19    /// No optimization
20    None,
21    /// Light optimization - fast passes only
22    Light,
23    /// Medium optimization - balanced
24    Medium,
25    /// Heavy optimization - all passes, may be slow
26    Heavy,
27    /// Custom optimization - user-defined passes
28    Custom,
29}
30
31/// Configuration for the pass manager
32#[derive(Debug, Clone)]
33pub struct PassConfig {
34    /// Maximum iterations for iterative passes
35    pub max_iterations: usize,
36    /// Enable aggressive optimizations
37    pub aggressive: bool,
38    /// Target gate set
39    pub target_gates: HashSet<String>,
40    /// Hardware backend name
41    pub backend: Option<String>,
42    /// Optimization level
43    pub level: OptimizationLevel,
44    /// Specific passes to disable
45    pub disabled_passes: HashSet<String>,
46}
47
48impl Default for PassConfig {
49    fn default() -> Self {
50        Self {
51            max_iterations: 10,
52            aggressive: false,
53            target_gates: HashSet::new(),
54            backend: None,
55            level: OptimizationLevel::Medium,
56            disabled_passes: HashSet::new(),
57        }
58    }
59}
60
61/// Pass manager that orchestrates optimization passes
62pub struct PassManager {
63    passes: Vec<Box<dyn OptimizationPass>>,
64    config: PassConfig,
65    applied_passes: Vec<String>,
66}
67
68impl PassManager {
69    /// Create a new pass manager with default configuration
70    #[must_use]
71    pub fn new() -> Self {
72        Self::with_level(OptimizationLevel::Medium)
73    }
74
75    /// Create a pass manager with a specific optimization level
76    #[must_use]
77    pub fn with_level(level: OptimizationLevel) -> Self {
78        let config = PassConfig {
79            level,
80            ..Default::default()
81        };
82
83        let passes = Self::create_passes_for_level(level, &config);
84
85        Self {
86            passes,
87            config,
88            applied_passes: Vec::new(),
89        }
90    }
91
92    /// Create a pass manager optimized for specific hardware
93    #[must_use]
94    pub fn for_hardware(hardware: &str) -> Self {
95        let mut config = PassConfig {
96            level: OptimizationLevel::Medium,
97            backend: Some(hardware.to_string()),
98            ..Default::default()
99        };
100
101        // Set hardware-specific target gates
102        config.target_gates = match hardware {
103            "ibm" => vec!["X", "Y", "Z", "H", "S", "T", "RZ", "CNOT", "CZ"]
104                .into_iter()
105                .map(std::string::ToString::to_string)
106                .collect(),
107            "google" => vec!["X", "Y", "Z", "H", "RZ", "CZ", "SQRT_X"]
108                .into_iter()
109                .map(std::string::ToString::to_string)
110                .collect(),
111            "aws" => vec!["X", "Y", "Z", "H", "RZ", "RX", "RY", "CNOT", "CZ"]
112                .into_iter()
113                .map(std::string::ToString::to_string)
114                .collect(),
115            _ => HashSet::new(),
116        };
117
118        let passes = Self::create_passes_for_hardware(hardware, &config);
119
120        Self {
121            passes,
122            config,
123            applied_passes: Vec::new(),
124        }
125    }
126
127    /// Configure the pass manager
128    pub fn configure(&mut self, config: PassConfig) {
129        self.config = config;
130        self.passes = Self::create_passes_for_level(self.config.level, &self.config);
131    }
132
133    /// Add a custom optimization pass
134    pub fn add_pass(&mut self, pass: Box<dyn OptimizationPass>) {
135        self.passes.push(pass);
136    }
137
138    /// Remove a pass by name
139    pub fn remove_pass(&mut self, name: &str) {
140        self.passes.retain(|p| p.name() != name);
141    }
142
143    /// Run all optimization passes on a circuit
144    pub fn run<const N: usize>(
145        &mut self,
146        circuit: &Circuit<N>,
147        cost_model: &dyn CostModel,
148    ) -> QuantRS2Result<Circuit<N>> {
149        self.applied_passes.clear();
150        let mut current_circuit = circuit.clone();
151        let mut iteration = 0;
152        let mut improved = true;
153
154        while improved && iteration < self.config.max_iterations {
155            improved = false;
156            let start_cost = cost_model.circuit_cost(&current_circuit);
157
158            for pass in &self.passes {
159                if self.config.disabled_passes.contains(pass.name()) {
160                    continue;
161                }
162
163                if pass.should_apply() {
164                    let optimized = pass.apply(&current_circuit, cost_model)?;
165                    let new_cost = cost_model.circuit_cost(&optimized);
166
167                    if new_cost < start_cost {
168                        current_circuit = optimized;
169                        self.applied_passes.push(pass.name().to_string());
170                        improved = true;
171                    }
172                }
173            }
174
175            iteration += 1;
176        }
177
178        Ok(current_circuit)
179    }
180
181    /// Get the list of applied passes
182    #[must_use]
183    pub fn get_applied_passes(&self) -> Vec<String> {
184        self.applied_passes.clone()
185    }
186
187    /// Create passes for a given optimization level
188    fn create_passes_for_level(
189        level: OptimizationLevel,
190        config: &PassConfig,
191    ) -> Vec<Box<dyn OptimizationPass>> {
192        match level {
193            OptimizationLevel::None => vec![],
194
195            OptimizationLevel::Light => vec![
196                Box::new(GateCancellation::new(false)),
197                Box::new(RotationMerging::new(1e-10)),
198            ],
199
200            OptimizationLevel::Medium => vec![
201                Box::new(GateCancellation::new(false)),
202                Box::new(GateCommutation::new(5)),
203                Box::new(PeepholeOptimization::new(3)),
204                Box::new(RotationMerging::new(1e-10)),
205                Box::new(GateMerging::new(true, 1e-10)),
206                Box::new(TemplateMatching::new()),
207            ],
208
209            OptimizationLevel::Heavy => vec![
210                Box::new(GateCancellation::new(true)),
211                Box::new(GateCommutation::new(10)),
212                Box::new(PeepholeOptimization::new(4)),
213                Box::new(RotationMerging::new(1e-12)),
214                Box::new(GateMerging::new(true, 1e-12)),
215                Box::new(DecompositionOptimization::new(
216                    config.target_gates.clone(),
217                    true,
218                )),
219                Box::new(TwoQubitOptimization::new(true, true)),
220                Box::new(TemplateMatching::new()),
221                Box::new(CircuitRewriting::new(100)),
222                Box::new(CostBasedOptimization::new(CostTarget::Balanced, 20)),
223            ],
224
225            OptimizationLevel::Custom => vec![],
226        }
227    }
228
229    /// Create passes optimized for specific hardware
230    fn create_passes_for_hardware(
231        hardware: &str,
232        config: &PassConfig,
233    ) -> Vec<Box<dyn OptimizationPass>> {
234        let mut passes: Vec<Box<dyn OptimizationPass>> = vec![
235            Box::new(GateCancellation::new(false)),
236            Box::new(GateCommutation::new(5)),
237            Box::new(PeepholeOptimization::new(3)),
238            Box::new(RotationMerging::new(1e-10)),
239        ];
240
241        match hardware {
242            "ibm" => {
243                passes.push(Box::new(DecompositionOptimization::for_hardware("ibm")));
244                passes.push(Box::new(TwoQubitOptimization::new(false, true)));
245            }
246            "google" => {
247                passes.push(Box::new(DecompositionOptimization::for_hardware("google")));
248                passes.push(Box::new(TwoQubitOptimization::new(true, false)));
249            }
250            "aws" => {
251                passes.push(Box::new(DecompositionOptimization::for_hardware("aws")));
252                passes.push(Box::new(CostBasedOptimization::new(
253                    CostTarget::TotalError,
254                    10,
255                )));
256            }
257            _ => {
258                passes.push(Box::new(DecompositionOptimization::new(
259                    config.target_gates.clone(),
260                    true,
261                )));
262            }
263        }
264
265        passes.push(Box::new(TemplateMatching::new()));
266        passes
267    }
268}
269
270impl Default for PassManager {
271    fn default() -> Self {
272        Self::new()
273    }
274}