1use crate::error::{QuantRS2Error, QuantRS2Result};
7use scirs2_core::Complex64;
8use std::collections::HashMap;
9use std::sync::{Arc, OnceLock, RwLock};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub enum GateType {
14 PauliX,
16 PauliY,
17 PauliZ,
18 Hadamard,
19 Phase(u64), RX(u64), RY(u64), RZ(u64), S,
24 T,
25
26 CNOT,
28 CZ,
29 SWAP,
30 CRZ(u64), Toffoli,
34 Fredkin,
35}
36
37#[derive(Debug, Clone)]
39pub struct QuantumGate {
40 pub gate_type: GateType,
41 pub qubits: Vec<usize>,
42 pub matrix: Vec<Complex64>,
43}
44
45impl QuantumGate {
46 pub fn new(gate_type: GateType, qubits: Vec<usize>) -> QuantRS2Result<Self> {
48 let matrix = Self::compute_matrix(&gate_type)?;
49 Ok(Self {
50 gate_type,
51 qubits,
52 matrix,
53 })
54 }
55
56 fn compute_matrix(gate_type: &GateType) -> QuantRS2Result<Vec<Complex64>> {
58 use std::f64::consts::{FRAC_1_SQRT_2, PI};
59
60 let matrix = match gate_type {
61 GateType::PauliX => vec![
62 Complex64::new(0.0, 0.0),
63 Complex64::new(1.0, 0.0),
64 Complex64::new(1.0, 0.0),
65 Complex64::new(0.0, 0.0),
66 ],
67 GateType::PauliY => vec![
68 Complex64::new(0.0, 0.0),
69 Complex64::new(0.0, -1.0),
70 Complex64::new(0.0, 1.0),
71 Complex64::new(0.0, 0.0),
72 ],
73 GateType::PauliZ => vec![
74 Complex64::new(1.0, 0.0),
75 Complex64::new(0.0, 0.0),
76 Complex64::new(0.0, 0.0),
77 Complex64::new(-1.0, 0.0),
78 ],
79 GateType::Hadamard => vec![
80 Complex64::new(FRAC_1_SQRT_2, 0.0),
81 Complex64::new(FRAC_1_SQRT_2, 0.0),
82 Complex64::new(FRAC_1_SQRT_2, 0.0),
83 Complex64::new(-FRAC_1_SQRT_2, 0.0),
84 ],
85 GateType::S => vec![
86 Complex64::new(1.0, 0.0),
87 Complex64::new(0.0, 0.0),
88 Complex64::new(0.0, 0.0),
89 Complex64::new(0.0, 1.0),
90 ],
91 GateType::T => vec![
92 Complex64::new(1.0, 0.0),
93 Complex64::new(0.0, 0.0),
94 Complex64::new(0.0, 0.0),
95 Complex64::new(FRAC_1_SQRT_2, FRAC_1_SQRT_2),
96 ],
97 GateType::RX(quantized_angle) => {
98 let angle = (*quantized_angle as f64) / 1_000_000.0;
99 let cos_half = (angle / 2.0).cos();
100 let sin_half = (angle / 2.0).sin();
101 vec![
102 Complex64::new(cos_half, 0.0),
103 Complex64::new(0.0, -sin_half),
104 Complex64::new(0.0, -sin_half),
105 Complex64::new(cos_half, 0.0),
106 ]
107 }
108 GateType::RY(quantized_angle) => {
109 let angle = (*quantized_angle as f64) / 1_000_000.0;
110 let cos_half = (angle / 2.0).cos();
111 let sin_half = (angle / 2.0).sin();
112 vec![
113 Complex64::new(cos_half, 0.0),
114 Complex64::new(-sin_half, 0.0),
115 Complex64::new(sin_half, 0.0),
116 Complex64::new(cos_half, 0.0),
117 ]
118 }
119 GateType::RZ(quantized_angle) => {
120 let angle = (*quantized_angle as f64) / 1_000_000.0;
121 let cos_half = (angle / 2.0).cos();
122 let sin_half = (angle / 2.0).sin();
123 vec![
124 Complex64::new(cos_half, -sin_half),
125 Complex64::new(0.0, 0.0),
126 Complex64::new(0.0, 0.0),
127 Complex64::new(cos_half, sin_half),
128 ]
129 }
130 GateType::Phase(quantized_angle) => {
131 let angle = (*quantized_angle as f64) / 1_000_000.0;
132 vec![
133 Complex64::new(1.0, 0.0),
134 Complex64::new(0.0, 0.0),
135 Complex64::new(0.0, 0.0),
136 Complex64::new(angle.cos(), angle.sin()),
137 ]
138 }
139 GateType::CNOT => vec![
140 Complex64::new(1.0, 0.0),
141 Complex64::new(0.0, 0.0),
142 Complex64::new(0.0, 0.0),
143 Complex64::new(0.0, 0.0),
144 Complex64::new(0.0, 0.0),
145 Complex64::new(1.0, 0.0),
146 Complex64::new(0.0, 0.0),
147 Complex64::new(0.0, 0.0),
148 Complex64::new(0.0, 0.0),
149 Complex64::new(0.0, 0.0),
150 Complex64::new(0.0, 0.0),
151 Complex64::new(1.0, 0.0),
152 Complex64::new(0.0, 0.0),
153 Complex64::new(0.0, 0.0),
154 Complex64::new(1.0, 0.0),
155 Complex64::new(0.0, 0.0),
156 ],
157 _ => return Err(QuantRS2Error::UnsupportedGate(format!("{:?}", gate_type))),
158 };
159
160 Ok(matrix)
161 }
162
163 pub fn num_qubits(&self) -> usize {
165 match self.gate_type {
166 GateType::PauliX
167 | GateType::PauliY
168 | GateType::PauliZ
169 | GateType::Hadamard
170 | GateType::Phase(_)
171 | GateType::RX(_)
172 | GateType::RY(_)
173 | GateType::RZ(_)
174 | GateType::S
175 | GateType::T => 1,
176
177 GateType::CNOT | GateType::CZ | GateType::SWAP | GateType::CRZ(_) => 2,
178
179 GateType::Toffoli | GateType::Fredkin => 3,
180 }
181 }
182}
183
184#[derive(Debug, Clone)]
186pub struct FusionRule {
187 pub pattern: Vec<GateType>,
188 pub replacement: Vec<GateType>,
189 pub efficiency_gain: f64, }
191
192impl FusionRule {
193 pub fn common_rules() -> Vec<FusionRule> {
195 vec![
196 FusionRule {
198 pattern: vec![GateType::PauliX, GateType::PauliX],
199 replacement: vec![], efficiency_gain: 2.0,
201 },
202 FusionRule {
204 pattern: vec![GateType::PauliY, GateType::PauliY],
205 replacement: vec![],
206 efficiency_gain: 2.0,
207 },
208 FusionRule {
210 pattern: vec![GateType::PauliZ, GateType::PauliZ],
211 replacement: vec![],
212 efficiency_gain: 2.0,
213 },
214 FusionRule {
216 pattern: vec![GateType::Hadamard, GateType::Hadamard],
217 replacement: vec![],
218 efficiency_gain: 2.0,
219 },
220 FusionRule {
222 pattern: vec![GateType::S, GateType::S],
223 replacement: vec![GateType::PauliZ],
224 efficiency_gain: 2.0,
225 },
226 FusionRule {
228 pattern: vec![GateType::T, GateType::T, GateType::T, GateType::T],
229 replacement: vec![],
230 efficiency_gain: 4.0,
231 },
232 ]
235 }
236}
237
238#[derive(Debug, Clone)]
240pub struct FusedGateSequence {
241 pub gates: Vec<QuantumGate>,
242 pub fused_matrix: Vec<Complex64>,
243 pub target_qubits: Vec<usize>,
244 pub efficiency_gain: f64,
245}
246
247impl FusedGateSequence {
248 pub fn from_gates(gates: Vec<QuantumGate>) -> QuantRS2Result<Self> {
250 if gates.is_empty() {
251 return Err(QuantRS2Error::InvalidInput(
252 "Empty gate sequence".to_string(),
253 ));
254 }
255
256 let target_qubits = gates[0].qubits.clone();
258 for gate in &gates {
259 if gate.qubits != target_qubits {
260 return Err(QuantRS2Error::InvalidInput(
261 "All gates must act on the same qubits for fusion".to_string(),
262 ));
263 }
264 }
265
266 let matrix_size = gates[0].matrix.len();
268 let sqrt_size = (matrix_size as f64).sqrt() as usize;
269
270 let mut fused_matrix = Self::identity_matrix(sqrt_size);
271
272 for gate in gates.iter().rev() {
274 fused_matrix = Self::matrix_multiply(&fused_matrix, &gate.matrix, sqrt_size)?;
275 }
276
277 let efficiency_gain = gates.len() as f64; Ok(Self {
280 gates,
281 fused_matrix,
282 target_qubits,
283 efficiency_gain,
284 })
285 }
286
287 fn identity_matrix(size: usize) -> Vec<Complex64> {
289 let mut matrix = vec![Complex64::new(0.0, 0.0); size * size];
290 for i in 0..size {
291 matrix[i * size + i] = Complex64::new(1.0, 0.0);
292 }
293 matrix
294 }
295
296 fn is_identity_matrix(&self) -> bool {
298 let size = (self.fused_matrix.len() as f64).sqrt() as usize;
299 let identity = Self::identity_matrix(size);
300
301 for (a, b) in self.fused_matrix.iter().zip(identity.iter()) {
302 if (a - b).norm() > 1e-10 {
303 return false;
304 }
305 }
306 true
307 }
308
309 fn matrix_multiply(
311 a: &[Complex64],
312 b: &[Complex64],
313 size: usize,
314 ) -> QuantRS2Result<Vec<Complex64>> {
315 if a.len() != size * size || b.len() != size * size {
316 return Err(QuantRS2Error::InvalidInput(
317 "Matrix size mismatch".to_string(),
318 ));
319 }
320
321 let mut result = vec![Complex64::new(0.0, 0.0); size * size];
322
323 for i in 0..size {
324 for j in 0..size {
325 for k in 0..size {
326 result[i * size + j] += a[i * size + k] * b[k * size + j];
327 }
328 }
329 }
330
331 Ok(result)
332 }
333}
334
335pub struct GateFusionEngine {
337 rules: Vec<FusionRule>,
338 statistics: Arc<RwLock<FusionStatistics>>,
339}
340
341#[derive(Debug, Clone, Default)]
343pub struct FusionStatistics {
344 pub total_fusions: u64,
345 pub gates_eliminated: u64,
346 pub total_efficiency_gain: f64,
347 pub fusion_types: HashMap<String, u64>,
348}
349
350impl GateFusionEngine {
351 pub fn new() -> Self {
353 Self {
354 rules: FusionRule::common_rules(),
355 statistics: Arc::new(RwLock::new(FusionStatistics::default())),
356 }
357 }
358
359 pub fn add_rule(&mut self, rule: FusionRule) {
361 self.rules.push(rule);
362 }
363
364 pub fn fuse_gates(&self, gates: Vec<QuantumGate>) -> QuantRS2Result<Vec<FusedGateSequence>> {
366 if gates.is_empty() {
367 return Ok(vec![]);
368 }
369
370 let mut fused_sequences = Vec::new();
371 let mut i = 0;
372
373 while i < gates.len() {
374 let gate = &gates[i];
375
376 if let Some(fusion_length) = self.find_fusion_pattern(&gates[i..]) {
378 let fusion_gates = gates[i..i + fusion_length].to_vec();
380 let fused_sequence = FusedGateSequence::from_gates(fusion_gates)?;
381
382 if !fused_sequence.is_identity_matrix() {
384 {
386 let mut stats = self.statistics.write().unwrap();
387 stats.total_fusions += 1;
388 stats.gates_eliminated += (fusion_length - 1) as u64;
389 stats.total_efficiency_gain += fused_sequence.efficiency_gain;
390
391 let fusion_type = format!("{:?}_fusion", gate.gate_type);
392 *stats.fusion_types.entry(fusion_type).or_insert(0) += 1;
393 }
394
395 fused_sequences.push(fused_sequence);
396 } else {
397 let mut stats = self.statistics.write().unwrap();
399 stats.total_fusions += 1;
400 stats.gates_eliminated += fusion_length as u64; }
402 i += fusion_length;
403 } else {
404 let mut gate_group = vec![gate.clone()];
406 let mut j = i + 1;
407
408 while j < gates.len() && gates[j].qubits == gate.qubits {
410 gate_group.push(gates[j].clone());
411 j += 1;
412 }
413
414 let fused_sequence = FusedGateSequence::from_gates(gate_group)?;
416 fused_sequences.push(fused_sequence);
417 i = j;
418 }
419 }
420
421 Ok(fused_sequences)
422 }
423
424 fn find_fusion_pattern(&self, gates: &[QuantumGate]) -> Option<usize> {
426 for rule in &self.rules {
427 if gates.len() >= rule.pattern.len() {
428 let matches = gates[..rule.pattern.len()]
429 .iter()
430 .zip(&rule.pattern)
431 .all(|(gate, pattern_gate)| gate.gate_type == *pattern_gate);
432
433 let same_qubits = if rule.pattern.len() > 1 {
435 let first_qubits = &gates[0].qubits;
436 gates[1..rule.pattern.len()]
437 .iter()
438 .all(|gate| gate.qubits == *first_qubits)
439 } else {
440 true };
442
443 if matches && same_qubits {
444 return Some(rule.pattern.len());
445 }
446 }
447 }
448
449 if gates.len() >= 2 {
451 let first = &gates[0];
452 if first.num_qubits() == 1 {
453 let mut count = 1;
454 for gate in gates.iter().skip(1) {
455 if gate.gate_type == first.gate_type && gate.qubits == first.qubits {
456 count += 1;
457 } else {
458 break;
459 }
460 }
461 if count > 1 {
462 return Some(count); }
464 }
465 }
466
467 None
468 }
469
470 pub fn get_statistics(&self) -> FusionStatistics {
472 self.statistics.read().unwrap().clone()
473 }
474
475 pub fn get_global_statistics() -> FusionStatistics {
477 if let Some(engine) = GLOBAL_FUSION_ENGINE.get() {
478 engine.get_statistics()
479 } else {
480 FusionStatistics::default()
481 }
482 }
483
484 pub fn reset_statistics(&self) {
486 let mut stats = self.statistics.write().unwrap();
487 *stats = FusionStatistics::default();
488 }
489}
490
491impl Default for GateFusionEngine {
492 fn default() -> Self {
493 Self::new()
494 }
495}
496
497static GLOBAL_FUSION_ENGINE: OnceLock<GateFusionEngine> = OnceLock::new();
499
500pub fn get_global_fusion_engine() -> &'static GateFusionEngine {
502 GLOBAL_FUSION_ENGINE.get_or_init(GateFusionEngine::new)
503}
504
505pub fn apply_gate_fusion(gates: Vec<QuantumGate>) -> QuantRS2Result<Vec<FusedGateSequence>> {
507 let engine = get_global_fusion_engine();
508 engine.fuse_gates(gates)
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514
515 #[test]
516 fn test_pauli_x_fusion() {
517 let gates = vec![
518 QuantumGate::new(GateType::PauliX, vec![0]).unwrap(),
519 QuantumGate::new(GateType::PauliX, vec![0]).unwrap(),
520 ];
521
522 let engine = GateFusionEngine::new();
523 let fused = engine.fuse_gates(gates).unwrap();
524
525 assert_eq!(fused.len(), 0);
527
528 let stats = engine.get_statistics();
529 assert_eq!(stats.gates_eliminated, 2);
530 }
531
532 #[test]
533 fn test_hadamard_fusion() {
534 let gates = vec![
535 QuantumGate::new(GateType::Hadamard, vec![0]).unwrap(),
536 QuantumGate::new(GateType::Hadamard, vec![0]).unwrap(),
537 ];
538
539 let engine = GateFusionEngine::new();
540 let fused = engine.fuse_gates(gates).unwrap();
541
542 assert_eq!(fused.len(), 0);
544 }
545
546 #[test]
547 fn test_mixed_gate_fusion() {
548 let gates = vec![
549 QuantumGate::new(GateType::PauliX, vec![0]).unwrap(),
550 QuantumGate::new(GateType::PauliY, vec![0]).unwrap(),
551 QuantumGate::new(GateType::PauliZ, vec![0]).unwrap(),
552 ];
553
554 let engine = GateFusionEngine::new();
555 let fused = engine.fuse_gates(gates).unwrap();
556
557 assert_eq!(fused.len(), 1);
559 assert_eq!(fused[0].gates.len(), 3);
560 }
561
562 #[test]
563 fn test_no_fusion_different_qubits() {
564 let gates = vec![
565 QuantumGate::new(GateType::PauliX, vec![0]).unwrap(),
566 QuantumGate::new(GateType::PauliX, vec![1]).unwrap(), ];
568
569 let engine = GateFusionEngine::new();
570 let fused = engine.fuse_gates(gates).unwrap();
571
572 assert_eq!(fused.len(), 2);
574 }
575
576 #[test]
577 fn test_matrix_multiplication() {
578 let identity = vec![
580 Complex64::new(1.0, 0.0),
581 Complex64::new(0.0, 0.0),
582 Complex64::new(0.0, 0.0),
583 Complex64::new(1.0, 0.0),
584 ];
585 let pauli_x = vec![
586 Complex64::new(0.0, 0.0),
587 Complex64::new(1.0, 0.0),
588 Complex64::new(1.0, 0.0),
589 Complex64::new(0.0, 0.0),
590 ];
591
592 let result = FusedGateSequence::matrix_multiply(&identity, &pauli_x, 2).unwrap();
593
594 for (a, b) in result.iter().zip(pauli_x.iter()) {
596 assert!((a - b).norm() < 1e-10);
597 }
598 }
599
600 #[test]
601 fn test_efficiency_gain_calculation() {
602 let gates = vec![
603 QuantumGate::new(GateType::S, vec![0]).unwrap(),
604 QuantumGate::new(GateType::T, vec![0]).unwrap(),
605 QuantumGate::new(GateType::Hadamard, vec![0]).unwrap(),
606 ];
607
608 let fused = FusedGateSequence::from_gates(gates).unwrap();
609 assert_eq!(fused.efficiency_gain, 3.0); }
611}