quantrs2_device/ml_optimization/
mod.rs1use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
8use std::f64::consts::PI;
9use std::sync::{Arc, Mutex, RwLock};
10use std::time::{Duration, Instant};
11
12use quantrs2_circuit::prelude::*;
13use quantrs2_core::{
14 error::{QuantRS2Error, QuantRS2Result},
15 gate::GateOp,
16 qubit::QubitId,
17};
18
19pub mod fallback_scirs2;
23pub use fallback_scirs2::*;
24
25use scirs2_core::ndarray::{s, Array1, Array2, Array3, Array4, ArrayView1, ArrayView2, Axis};
26use scirs2_core::random::prelude::*;
27use scirs2_core::Complex64;
28use tokio::sync::{broadcast, mpsc};
29
30use crate::{
31 adaptive_compilation::AdaptiveCompilationConfig,
32 backend_traits::{query_backend_capabilities, BackendCapabilities},
33 calibration::{CalibrationManager, DeviceCalibration},
34 integrated_device_manager::IntegratedQuantumDeviceManager,
35 noise_model::CalibrationNoiseModel,
36 topology::HardwareTopology,
37 CircuitResult, DeviceError, DeviceResult,
38};
39
40pub mod config;
42pub mod ensemble;
43pub mod features;
44pub mod hardware;
45pub mod monitoring;
46pub mod online_learning;
47pub mod optimization;
48pub mod training;
49pub mod transfer_learning;
50pub mod validation;
51
52#[cfg(not(feature = "scirs2"))]
53pub mod fallback;
54
55pub use config::*;
57pub use ensemble::*;
58pub use features::*;
59pub use hardware::*;
60pub use monitoring::*;
61pub use online_learning::*;
62pub use optimization::*;
63pub use training::*;
64pub use transfer_learning::*;
65pub use validation::*;
66
67#[cfg(not(feature = "scirs2"))]
68pub use fallback::*;
69
70#[derive(Debug, Clone, PartialEq, Eq)]
75pub enum MLOptimizationStrategy {
76 MinimizeGateCount,
78 MinimizeDepth,
80 BalancedOptimization,
82}
83
84impl Default for MLOptimizationStrategy {
85 fn default() -> Self {
86 MLOptimizationStrategy::BalancedOptimization
87 }
88}
89
90#[derive(Debug, Clone)]
92pub struct CircuitScore {
93 pub two_qubit_gate_count: usize,
95 pub total_gate_count: usize,
97 pub circuit_depth: usize,
99 pub composite: f64,
101}
102
103impl CircuitScore {
104 pub fn compute<const N: usize>(
106 circuit: &quantrs2_circuit::prelude::Circuit<N>,
107 strategy: &MLOptimizationStrategy,
108 ) -> Self {
109 let gates = circuit.gates();
110 let total = gates.len();
111 let two_q = gates.iter().filter(|g| g.qubits().len() == 2).count();
112
113 let mut qubit_depth = vec![0usize; N];
115 for gate in gates {
116 let max_d = gate
117 .qubits()
118 .iter()
119 .map(|q| qubit_depth.get(q.id() as usize).copied().unwrap_or(0))
120 .max()
121 .unwrap_or(0);
122 for q in gate.qubits() {
123 let idx = q.id() as usize;
124 if idx < N {
125 qubit_depth[idx] = max_d + 1;
126 }
127 }
128 }
129 let depth = qubit_depth.iter().copied().max().unwrap_or(0);
130
131 let composite = match strategy {
132 MLOptimizationStrategy::MinimizeGateCount => total as f64,
133 MLOptimizationStrategy::MinimizeDepth => depth as f64,
134 MLOptimizationStrategy::BalancedOptimization => {
135 (two_q as f64) * 10.0 + (total as f64) + (depth as f64)
137 }
138 };
139
140 Self {
141 two_qubit_gate_count: two_q,
142 total_gate_count: total,
143 circuit_depth: depth,
144 composite,
145 }
146 }
147}
148
149pub struct MLCircuitOptimizer {
163 pub strategy: MLOptimizationStrategy,
165 pub max_passes: usize,
167 pub convergence_threshold: f64,
169}
170
171impl MLCircuitOptimizer {
172 pub fn new(strategy: MLOptimizationStrategy) -> Self {
174 Self {
175 strategy,
176 max_passes: 5,
177 convergence_threshold: 0.01,
178 }
179 }
180
181 pub fn with_passes(mut self, passes: usize) -> Self {
183 self.max_passes = passes;
184 self
185 }
186
187 pub fn optimize<const N: usize>(
194 &self,
195 circuit: &quantrs2_circuit::prelude::Circuit<N>,
196 ) -> QuantRS2Result<quantrs2_circuit::prelude::Circuit<N>> {
197 use crate::transpiler_scirs2_graph::{SciRS2GraphTranspiler, SciRS2TranspilerConfig};
198
199 let transpiler = SciRS2GraphTranspiler::new(SciRS2TranspilerConfig {
200 enable_commutation: true,
201 enable_critical_path_opt: true,
202 enable_routing_opt: false,
203 max_optimization_passes: self.max_passes,
204 hardware_topology: None,
205 });
206
207 let mut best = circuit.clone();
208 let mut best_score = CircuitScore::compute(&best, &self.strategy);
209
210 for _pass in 0..self.max_passes {
211 let candidate = transpiler.optimize_circuit(&best).map_err(|e| {
213 QuantRS2Error::InvalidInput(format!("ML optimizer pass failed: {}", e))
214 })?;
215
216 let candidate_score = CircuitScore::compute(&candidate, &self.strategy);
217
218 let improvement =
220 (best_score.composite - candidate_score.composite) / best_score.composite.max(1.0);
221
222 if candidate_score.composite < best_score.composite {
223 best = candidate;
224 best_score = candidate_score;
225 if improvement < self.convergence_threshold {
226 break; }
228 } else {
229 break; }
231 }
232
233 Ok(best)
234 }
235
236 pub fn score<const N: usize>(
238 &self,
239 circuit: &quantrs2_circuit::prelude::Circuit<N>,
240 ) -> CircuitScore {
241 CircuitScore::compute(circuit, &self.strategy)
242 }
243}
244
245#[cfg(test)]
246mod ml_optimizer_tests {
247 use super::*;
248 use quantrs2_circuit::prelude::Circuit;
249
250 #[test]
251 fn test_ml_optimizer_creation() {
252 let opt = MLCircuitOptimizer::new(MLOptimizationStrategy::MinimizeGateCount);
253 assert_eq!(opt.strategy, MLOptimizationStrategy::MinimizeGateCount);
254 assert_eq!(opt.max_passes, 5);
255 }
256
257 #[test]
258 fn test_circuit_score_basic() {
259 let mut circuit = Circuit::<2>::new();
260 let _ = circuit.h(0);
261 let _ = circuit.cnot(0, 1);
262
263 let score = CircuitScore::compute(&circuit, &MLOptimizationStrategy::BalancedOptimization);
264 assert_eq!(score.total_gate_count, 2);
265 assert_eq!(score.two_qubit_gate_count, 1);
266 assert!(score.composite > 0.0);
267 }
268
269 #[test]
270 fn test_ml_optimizer_optimize() {
271 let opt = MLCircuitOptimizer::new(MLOptimizationStrategy::BalancedOptimization);
272
273 let mut circuit = Circuit::<3>::new();
274 let _ = circuit.h(0);
275 let _ = circuit.h(1);
276 let _ = circuit.cnot(0, 1);
277 let _ = circuit.cnot(1, 2);
278
279 let result = opt.optimize(&circuit);
280 assert!(result.is_ok(), "Optimization should succeed");
281 let optimized = result.expect("Optimized circuit");
282 assert!(
283 !optimized.gates().is_empty(),
284 "Optimized circuit should have gates"
285 );
286 }
287
288 #[test]
289 fn test_minimize_depth_strategy() {
290 let opt = MLCircuitOptimizer::new(MLOptimizationStrategy::MinimizeDepth);
291 let mut circuit = Circuit::<2>::new();
292 let _ = circuit.h(0);
293 let _ = circuit.h(1);
294
295 let score = opt.score(&circuit);
296 assert_eq!(score.circuit_depth, 1);
298 }
299}