1use quantrs2_core::error::{QuantRS2Error, QuantRS2Result};
16use scirs2_core::ndarray::{Array1, Array2};
17use scirs2_core::Complex64;
18use serde::{Deserialize, Serialize};
19use std::collections::HashMap;
20use std::sync::{Arc, Mutex, RwLock};
21use std::time::{Duration, Instant};
22
23#[derive(Debug)]
25pub struct GPUKernelOptimizer {
26 kernel_registry: KernelRegistry,
28 stats: Arc<Mutex<KernelStats>>,
30 config: GPUKernelConfig,
32 kernel_cache: Arc<RwLock<HashMap<String, CompiledKernel>>>,
34 memory_optimizer: MemoryLayoutOptimizer,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct GPUKernelConfig {
41 pub enable_warp_optimization: bool,
43 pub enable_shared_memory: bool,
45 pub block_size: usize,
47 pub grid_size_method: GridSizeMethod,
49 pub enable_kernel_fusion: bool,
51 pub max_fusion_length: usize,
53 pub enable_memory_coalescing: bool,
55 pub enable_streaming: bool,
57 pub num_streams: usize,
59 pub target_occupancy: f64,
61}
62
63impl Default for GPUKernelConfig {
64 fn default() -> Self {
65 Self {
66 enable_warp_optimization: true,
67 enable_shared_memory: true,
68 block_size: 256,
69 grid_size_method: GridSizeMethod::Automatic,
70 enable_kernel_fusion: true,
71 max_fusion_length: 8,
72 enable_memory_coalescing: true,
73 enable_streaming: true,
74 num_streams: 4,
75 target_occupancy: 0.75,
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
82pub enum GridSizeMethod {
83 Automatic,
85 Fixed(usize),
87 OccupancyBased,
89}
90
91#[derive(Debug)]
93pub struct KernelRegistry {
94 single_qubit_kernels: HashMap<String, SingleQubitKernel>,
96 two_qubit_kernels: HashMap<String, TwoQubitKernel>,
98 fused_kernels: HashMap<String, FusedKernel>,
100 custom_kernels: HashMap<String, CustomKernel>,
102}
103
104impl Default for KernelRegistry {
105 fn default() -> Self {
106 let mut registry = Self {
107 single_qubit_kernels: HashMap::new(),
108 two_qubit_kernels: HashMap::new(),
109 fused_kernels: HashMap::new(),
110 custom_kernels: HashMap::new(),
111 };
112 registry.register_builtin_kernels();
113 registry
114 }
115}
116
117impl KernelRegistry {
118 fn register_builtin_kernels(&mut self) {
120 self.single_qubit_kernels.insert(
122 "hadamard".to_string(),
123 SingleQubitKernel {
124 name: "hadamard".to_string(),
125 kernel_type: SingleQubitKernelType::Hadamard,
126 optimization_level: OptimizationLevel::Maximum,
127 uses_shared_memory: true,
128 register_usage: 32,
129 },
130 );
131
132 self.single_qubit_kernels.insert(
133 "pauli_x".to_string(),
134 SingleQubitKernel {
135 name: "pauli_x".to_string(),
136 kernel_type: SingleQubitKernelType::PauliX,
137 optimization_level: OptimizationLevel::Maximum,
138 uses_shared_memory: false, register_usage: 16,
140 },
141 );
142
143 self.single_qubit_kernels.insert(
144 "pauli_y".to_string(),
145 SingleQubitKernel {
146 name: "pauli_y".to_string(),
147 kernel_type: SingleQubitKernelType::PauliY,
148 optimization_level: OptimizationLevel::Maximum,
149 uses_shared_memory: false,
150 register_usage: 24,
151 },
152 );
153
154 self.single_qubit_kernels.insert(
155 "pauli_z".to_string(),
156 SingleQubitKernel {
157 name: "pauli_z".to_string(),
158 kernel_type: SingleQubitKernelType::PauliZ,
159 optimization_level: OptimizationLevel::Maximum,
160 uses_shared_memory: false,
161 register_usage: 16,
162 },
163 );
164
165 self.single_qubit_kernels.insert(
166 "phase".to_string(),
167 SingleQubitKernel {
168 name: "phase".to_string(),
169 kernel_type: SingleQubitKernelType::Phase,
170 optimization_level: OptimizationLevel::High,
171 uses_shared_memory: false,
172 register_usage: 24,
173 },
174 );
175
176 self.single_qubit_kernels.insert(
177 "t_gate".to_string(),
178 SingleQubitKernel {
179 name: "t_gate".to_string(),
180 kernel_type: SingleQubitKernelType::TGate,
181 optimization_level: OptimizationLevel::High,
182 uses_shared_memory: false,
183 register_usage: 24,
184 },
185 );
186
187 self.single_qubit_kernels.insert(
188 "rotation_x".to_string(),
189 SingleQubitKernel {
190 name: "rotation_x".to_string(),
191 kernel_type: SingleQubitKernelType::RotationX,
192 optimization_level: OptimizationLevel::Medium,
193 uses_shared_memory: true,
194 register_usage: 40,
195 },
196 );
197
198 self.single_qubit_kernels.insert(
199 "rotation_y".to_string(),
200 SingleQubitKernel {
201 name: "rotation_y".to_string(),
202 kernel_type: SingleQubitKernelType::RotationY,
203 optimization_level: OptimizationLevel::Medium,
204 uses_shared_memory: true,
205 register_usage: 40,
206 },
207 );
208
209 self.single_qubit_kernels.insert(
210 "rotation_z".to_string(),
211 SingleQubitKernel {
212 name: "rotation_z".to_string(),
213 kernel_type: SingleQubitKernelType::RotationZ,
214 optimization_level: OptimizationLevel::Medium,
215 uses_shared_memory: true,
216 register_usage: 32,
217 },
218 );
219
220 self.two_qubit_kernels.insert(
222 "cnot".to_string(),
223 TwoQubitKernel {
224 name: "cnot".to_string(),
225 kernel_type: TwoQubitKernelType::CNOT,
226 optimization_level: OptimizationLevel::Maximum,
227 uses_shared_memory: true,
228 register_usage: 48,
229 memory_access_pattern: MemoryAccessPattern::Strided,
230 },
231 );
232
233 self.two_qubit_kernels.insert(
234 "cz".to_string(),
235 TwoQubitKernel {
236 name: "cz".to_string(),
237 kernel_type: TwoQubitKernelType::CZ,
238 optimization_level: OptimizationLevel::Maximum,
239 uses_shared_memory: false,
240 register_usage: 32,
241 memory_access_pattern: MemoryAccessPattern::Sparse,
242 },
243 );
244
245 self.two_qubit_kernels.insert(
246 "swap".to_string(),
247 TwoQubitKernel {
248 name: "swap".to_string(),
249 kernel_type: TwoQubitKernelType::SWAP,
250 optimization_level: OptimizationLevel::High,
251 uses_shared_memory: true,
252 register_usage: 40,
253 memory_access_pattern: MemoryAccessPattern::Strided,
254 },
255 );
256
257 self.two_qubit_kernels.insert(
258 "iswap".to_string(),
259 TwoQubitKernel {
260 name: "iswap".to_string(),
261 kernel_type: TwoQubitKernelType::ISWAP,
262 optimization_level: OptimizationLevel::High,
263 uses_shared_memory: true,
264 register_usage: 48,
265 memory_access_pattern: MemoryAccessPattern::Strided,
266 },
267 );
268
269 self.two_qubit_kernels.insert(
270 "controlled_rotation".to_string(),
271 TwoQubitKernel {
272 name: "controlled_rotation".to_string(),
273 kernel_type: TwoQubitKernelType::ControlledRotation,
274 optimization_level: OptimizationLevel::Medium,
275 uses_shared_memory: true,
276 register_usage: 56,
277 memory_access_pattern: MemoryAccessPattern::Strided,
278 },
279 );
280
281 self.fused_kernels.insert(
283 "h_cnot_h".to_string(),
284 FusedKernel {
285 name: "h_cnot_h".to_string(),
286 sequence: vec![
287 "hadamard".to_string(),
288 "cnot".to_string(),
289 "hadamard".to_string(),
290 ],
291 optimization_gain: 2.5,
292 register_usage: 64,
293 },
294 );
295
296 self.fused_kernels.insert(
297 "rotation_chain".to_string(),
298 FusedKernel {
299 name: "rotation_chain".to_string(),
300 sequence: vec![
301 "rotation_x".to_string(),
302 "rotation_y".to_string(),
303 "rotation_z".to_string(),
304 ],
305 optimization_gain: 2.0,
306 register_usage: 56,
307 },
308 );
309
310 self.fused_kernels.insert(
311 "bell_state".to_string(),
312 FusedKernel {
313 name: "bell_state".to_string(),
314 sequence: vec!["hadamard".to_string(), "cnot".to_string()],
315 optimization_gain: 1.8,
316 register_usage: 48,
317 },
318 );
319 }
320}
321
322#[derive(Debug, Clone)]
324pub struct SingleQubitKernel {
325 pub name: String,
327 pub kernel_type: SingleQubitKernelType,
329 pub optimization_level: OptimizationLevel,
331 pub uses_shared_memory: bool,
333 pub register_usage: usize,
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq)]
339pub enum SingleQubitKernelType {
340 Hadamard,
341 PauliX,
342 PauliY,
343 PauliZ,
344 Phase,
345 TGate,
346 RotationX,
347 RotationY,
348 RotationZ,
349 Generic,
350}
351
352#[derive(Debug, Clone)]
354pub struct TwoQubitKernel {
355 pub name: String,
357 pub kernel_type: TwoQubitKernelType,
359 pub optimization_level: OptimizationLevel,
361 pub uses_shared_memory: bool,
363 pub register_usage: usize,
365 pub memory_access_pattern: MemoryAccessPattern,
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum TwoQubitKernelType {
372 CNOT,
373 CZ,
374 SWAP,
375 ISWAP,
376 ControlledRotation,
377 Generic,
378}
379
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum MemoryAccessPattern {
383 Coalesced,
385 Strided,
387 Sparse,
389 Random,
391}
392
393#[derive(Debug, Clone)]
395pub struct FusedKernel {
396 pub name: String,
398 pub sequence: Vec<String>,
400 pub optimization_gain: f64,
402 pub register_usage: usize,
404}
405
406#[derive(Debug, Clone)]
408pub struct CustomKernel {
409 pub name: String,
411 pub code: String,
413 pub register_usage: usize,
415}
416
417#[derive(Debug, Clone)]
419pub struct CompiledKernel {
420 pub name: String,
422 pub compiled_code: Vec<u8>,
424 pub exec_params: KernelExecParams,
426}
427
428#[derive(Debug, Clone)]
430pub struct KernelExecParams {
431 pub block_dim: (usize, usize, usize),
433 pub grid_dim: (usize, usize, usize),
435 pub shared_memory_size: usize,
437 pub max_threads_per_block: usize,
439}
440
441#[derive(Debug, Clone, Copy, PartialEq, Eq)]
443pub enum OptimizationLevel {
444 Basic,
446 Medium,
448 High,
450 Maximum,
452}
453
454#[derive(Debug, Clone, Default)]
456pub struct KernelStats {
457 pub total_executions: u64,
459 pub total_execution_time: Duration,
461 pub execution_counts: HashMap<String, u64>,
463 pub execution_times: HashMap<String, Duration>,
465 pub cache_hits: u64,
467 pub cache_misses: u64,
469 pub fused_operations: u64,
471 pub memory_bandwidth: f64,
473 pub compute_throughput: f64,
475}
476
477#[derive(Debug)]
479pub struct MemoryLayoutOptimizer {
480 strategy: MemoryLayoutStrategy,
482 prefetch_distance: usize,
484}
485
486#[derive(Debug, Clone, Copy)]
488pub enum MemoryLayoutStrategy {
489 Interleaved,
491 SplitArrays,
493 StructureOfArrays,
495 ArrayOfStructures,
497}
498
499impl Default for MemoryLayoutOptimizer {
500 fn default() -> Self {
501 Self {
502 strategy: MemoryLayoutStrategy::Interleaved,
503 prefetch_distance: 4,
504 }
505 }
506}
507
508impl GPUKernelOptimizer {
509 #[must_use]
511 pub fn new(config: GPUKernelConfig) -> Self {
512 Self {
513 kernel_registry: KernelRegistry::default(),
514 stats: Arc::new(Mutex::new(KernelStats::default())),
515 config,
516 kernel_cache: Arc::new(RwLock::new(HashMap::new())),
517 memory_optimizer: MemoryLayoutOptimizer::default(),
518 }
519 }
520
521 pub fn apply_single_qubit_gate(
523 &mut self,
524 state: &mut Array1<Complex64>,
525 qubit: usize,
526 gate_name: &str,
527 parameters: Option<&[f64]>,
528 ) -> QuantRS2Result<()> {
529 let start = Instant::now();
530
531 let kernel = self.kernel_registry.single_qubit_kernels.get(gate_name);
533
534 let n = state.len();
535 let stride = 1 << qubit;
536
537 match kernel {
538 Some(k) => {
539 match k.kernel_type {
541 SingleQubitKernelType::Hadamard => {
542 self.apply_hadamard_optimized(state, stride)?;
543 }
544 SingleQubitKernelType::PauliX => {
545 self.apply_pauli_x_optimized(state, stride)?;
546 }
547 SingleQubitKernelType::PauliY => {
548 self.apply_pauli_y_optimized(state, stride)?;
549 }
550 SingleQubitKernelType::PauliZ => {
551 self.apply_pauli_z_optimized(state, stride)?;
552 }
553 SingleQubitKernelType::Phase => {
554 self.apply_phase_optimized(state, stride)?;
555 }
556 SingleQubitKernelType::TGate => {
557 self.apply_t_gate_optimized(state, stride)?;
558 }
559 SingleQubitKernelType::RotationX => {
560 let angle = parameters.and_then(|p| p.first()).copied().unwrap_or(0.0);
561 self.apply_rotation_x_optimized(state, stride, angle)?;
562 }
563 SingleQubitKernelType::RotationY => {
564 let angle = parameters.and_then(|p| p.first()).copied().unwrap_or(0.0);
565 self.apply_rotation_y_optimized(state, stride, angle)?;
566 }
567 SingleQubitKernelType::RotationZ => {
568 let angle = parameters.and_then(|p| p.first()).copied().unwrap_or(0.0);
569 self.apply_rotation_z_optimized(state, stride, angle)?;
570 }
571 SingleQubitKernelType::Generic => {
572 self.apply_generic_single_qubit(state, qubit, gate_name, parameters)?;
574 }
575 }
576 }
577 None => {
578 self.apply_generic_single_qubit(state, qubit, gate_name, parameters)?;
580 }
581 }
582
583 let mut stats = self
585 .stats
586 .lock()
587 .map_err(|_| QuantRS2Error::InvalidInput("Failed to acquire stats lock".to_string()))?;
588 stats.total_executions += 1;
589 stats.total_execution_time += start.elapsed();
590 *stats
591 .execution_counts
592 .entry(gate_name.to_string())
593 .or_insert(0) += 1;
594 *stats
595 .execution_times
596 .entry(gate_name.to_string())
597 .or_insert(Duration::ZERO) += start.elapsed();
598
599 Ok(())
600 }
601
602 fn apply_hadamard_optimized(
604 &self,
605 state: &mut Array1<Complex64>,
606 stride: usize,
607 ) -> QuantRS2Result<()> {
608 let n = state.len();
609 let inv_sqrt2 = 1.0 / 2.0_f64.sqrt();
610
611 let amplitudes = state.as_slice_mut().ok_or_else(|| {
612 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
613 })?;
614
615 for i in 0..n / 2 {
617 let i0 = (i / stride) * (2 * stride) + (i % stride);
618 let i1 = i0 + stride;
619
620 let a0 = amplitudes[i0];
621 let a1 = amplitudes[i1];
622
623 amplitudes[i0] =
624 Complex64::new((a0.re + a1.re) * inv_sqrt2, (a0.im + a1.im) * inv_sqrt2);
625 amplitudes[i1] =
626 Complex64::new((a0.re - a1.re) * inv_sqrt2, (a0.im - a1.im) * inv_sqrt2);
627 }
628
629 Ok(())
630 }
631
632 fn apply_pauli_x_optimized(
634 &self,
635 state: &mut Array1<Complex64>,
636 stride: usize,
637 ) -> QuantRS2Result<()> {
638 let n = state.len();
639
640 let amplitudes = state.as_slice_mut().ok_or_else(|| {
641 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
642 })?;
643
644 for i in 0..n / 2 {
646 let i0 = (i / stride) * (2 * stride) + (i % stride);
647 let i1 = i0 + stride;
648
649 amplitudes.swap(i0, i1);
650 }
651
652 Ok(())
653 }
654
655 fn apply_pauli_y_optimized(
657 &self,
658 state: &mut Array1<Complex64>,
659 stride: usize,
660 ) -> QuantRS2Result<()> {
661 let n = state.len();
662
663 let amplitudes = state.as_slice_mut().ok_or_else(|| {
664 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
665 })?;
666
667 for i in 0..n / 2 {
668 let i0 = (i / stride) * (2 * stride) + (i % stride);
669 let i1 = i0 + stride;
670
671 let a0 = amplitudes[i0];
672 let a1 = amplitudes[i1];
673
674 amplitudes[i0] = Complex64::new(a1.im, -a1.re);
676 amplitudes[i1] = Complex64::new(-a0.im, a0.re);
677 }
678
679 Ok(())
680 }
681
682 fn apply_pauli_z_optimized(
684 &self,
685 state: &mut Array1<Complex64>,
686 stride: usize,
687 ) -> QuantRS2Result<()> {
688 let n = state.len();
689
690 let amplitudes = state.as_slice_mut().ok_or_else(|| {
691 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
692 })?;
693
694 for i in 0..n / 2 {
696 let i1 = (i / stride) * (2 * stride) + (i % stride) + stride;
697 amplitudes[i1] = -amplitudes[i1];
698 }
699
700 Ok(())
701 }
702
703 fn apply_phase_optimized(
705 &self,
706 state: &mut Array1<Complex64>,
707 stride: usize,
708 ) -> QuantRS2Result<()> {
709 let n = state.len();
710
711 let amplitudes = state.as_slice_mut().ok_or_else(|| {
712 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
713 })?;
714
715 for i in 0..n / 2 {
717 let i1 = (i / stride) * (2 * stride) + (i % stride) + stride;
718 let a = amplitudes[i1];
719 amplitudes[i1] = Complex64::new(-a.im, a.re); }
721
722 Ok(())
723 }
724
725 fn apply_t_gate_optimized(
727 &self,
728 state: &mut Array1<Complex64>,
729 stride: usize,
730 ) -> QuantRS2Result<()> {
731 let n = state.len();
732 let t_phase = Complex64::new(
733 std::f64::consts::FRAC_1_SQRT_2,
734 std::f64::consts::FRAC_1_SQRT_2,
735 );
736
737 let amplitudes = state.as_slice_mut().ok_or_else(|| {
738 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
739 })?;
740
741 for i in 0..n / 2 {
743 let i1 = (i / stride) * (2 * stride) + (i % stride) + stride;
744 amplitudes[i1] *= t_phase;
745 }
746
747 Ok(())
748 }
749
750 fn apply_rotation_x_optimized(
752 &self,
753 state: &mut Array1<Complex64>,
754 stride: usize,
755 angle: f64,
756 ) -> QuantRS2Result<()> {
757 let n = state.len();
758 let cos_half = (angle / 2.0).cos();
759 let sin_half = (angle / 2.0).sin();
760
761 let amplitudes = state.as_slice_mut().ok_or_else(|| {
762 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
763 })?;
764
765 for i in 0..n / 2 {
766 let i0 = (i / stride) * (2 * stride) + (i % stride);
767 let i1 = i0 + stride;
768
769 let a0 = amplitudes[i0];
770 let a1 = amplitudes[i1];
771
772 amplitudes[i0] = Complex64::new(
774 cos_half * a0.re + sin_half * a1.im,
775 cos_half * a0.im - sin_half * a1.re,
776 );
777 amplitudes[i1] = Complex64::new(
778 sin_half * a0.im + cos_half * a1.re,
779 (-sin_half).mul_add(a0.re, cos_half * a1.im),
780 );
781 }
782
783 Ok(())
784 }
785
786 fn apply_rotation_y_optimized(
788 &self,
789 state: &mut Array1<Complex64>,
790 stride: usize,
791 angle: f64,
792 ) -> QuantRS2Result<()> {
793 let n = state.len();
794 let cos_half = (angle / 2.0).cos();
795 let sin_half = (angle / 2.0).sin();
796
797 let amplitudes = state.as_slice_mut().ok_or_else(|| {
798 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
799 })?;
800
801 for i in 0..n / 2 {
802 let i0 = (i / stride) * (2 * stride) + (i % stride);
803 let i1 = i0 + stride;
804
805 let a0 = amplitudes[i0];
806 let a1 = amplitudes[i1];
807
808 amplitudes[i0] = Complex64::new(
810 cos_half * a0.re - sin_half * a1.re,
811 cos_half * a0.im - sin_half * a1.im,
812 );
813 amplitudes[i1] = Complex64::new(
814 sin_half * a0.re + cos_half * a1.re,
815 sin_half * a0.im + cos_half * a1.im,
816 );
817 }
818
819 Ok(())
820 }
821
822 fn apply_rotation_z_optimized(
824 &self,
825 state: &mut Array1<Complex64>,
826 stride: usize,
827 angle: f64,
828 ) -> QuantRS2Result<()> {
829 let n = state.len();
830 let exp_neg = Complex64::new((angle / 2.0).cos(), -(angle / 2.0).sin());
831 let exp_pos = Complex64::new((angle / 2.0).cos(), (angle / 2.0).sin());
832
833 let amplitudes = state.as_slice_mut().ok_or_else(|| {
834 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
835 })?;
836
837 for i in 0..n / 2 {
838 let i0 = (i / stride) * (2 * stride) + (i % stride);
839 let i1 = i0 + stride;
840
841 amplitudes[i0] *= exp_neg;
843 amplitudes[i1] *= exp_pos;
844 }
845
846 Ok(())
847 }
848
849 fn apply_generic_single_qubit(
859 &self,
860 state: &mut Array1<Complex64>,
861 qubit: usize,
862 gate_name: &str,
863 parameters: Option<&[f64]>,
864 ) -> QuantRS2Result<()> {
865 let stride = 1usize << qubit;
866 let matrix = Self::single_qubit_matrix_for_name(gate_name, parameters)?;
867 Self::apply_matrix2_optimized(state, stride, &matrix)
868 }
869
870 fn single_qubit_matrix_for_name(
875 gate_name: &str,
876 parameters: Option<&[f64]>,
877 ) -> QuantRS2Result<[[Complex64; 2]; 2]> {
878 let one = Complex64::new(1.0, 0.0);
879 let zero = Complex64::new(0.0, 0.0);
880 match gate_name {
881 "I" | "Identity" | "identity" => Ok([[one, zero], [zero, one]]),
882 "S†" | "Sdg" | "SDagger" | "SDG" | "s_dagger" | "sdg" => {
883 Ok([[one, zero], [zero, Complex64::new(0.0, -1.0)]])
884 }
885 "T†" | "Tdg" | "TDagger" | "TDG" | "t_dagger" | "tdg" => Ok([
886 [one, zero],
887 [
888 zero,
889 Complex64::from_polar(1.0, -std::f64::consts::FRAC_PI_4),
890 ],
891 ]),
892 "√X" | "SqrtX" | "SX" | "sqrt_x" | "sx" => {
893 let plus = Complex64::new(0.5, 0.5);
894 let minus = Complex64::new(0.5, -0.5);
895 Ok([[plus, minus], [minus, plus]])
896 }
897 "√X†" | "SqrtXdg" | "SXDG" | "sqrt_x_dagger" | "sxdg" => {
898 let plus = Complex64::new(0.5, -0.5);
899 let minus = Complex64::new(0.5, 0.5);
900 Ok([[plus, minus], [minus, plus]])
901 }
902 "P" | "Phase" | "U1" | "phase_shift" | "u1" => {
903 let theta = parameters.and_then(|p| p.first()).copied().ok_or_else(|| {
904 QuantRS2Error::InvalidInput(format!(
905 "gate '{gate_name}' requires a phase-angle parameter"
906 ))
907 })?;
908 Ok([[one, zero], [zero, Complex64::from_polar(1.0, theta)]])
909 }
910 _ => Err(QuantRS2Error::UnsupportedOperation(format!(
911 "gpu_kernel_optimization: no real matrix implementation for single-qubit gate \
912 '{gate_name}'; add a specialized or generic-matrix case instead of a silent \
913 no-op"
914 ))),
915 }
916 }
917
918 fn apply_matrix2_optimized(
922 state: &mut Array1<Complex64>,
923 stride: usize,
924 matrix: &[[Complex64; 2]; 2],
925 ) -> QuantRS2Result<()> {
926 let n = state.len();
927 let amplitudes = state.as_slice_mut().ok_or_else(|| {
928 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
929 })?;
930
931 for i in 0..n / 2 {
932 let i0 = (i / stride) * (2 * stride) + (i % stride);
933 let i1 = i0 + stride;
934
935 let a0 = amplitudes[i0];
936 let a1 = amplitudes[i1];
937
938 amplitudes[i0] = matrix[0][0] * a0 + matrix[0][1] * a1;
939 amplitudes[i1] = matrix[1][0] * a0 + matrix[1][1] * a1;
940 }
941
942 Ok(())
943 }
944
945 pub fn apply_two_qubit_gate(
947 &mut self,
948 state: &mut Array1<Complex64>,
949 control: usize,
950 target: usize,
951 gate_name: &str,
952 ) -> QuantRS2Result<()> {
953 let start = Instant::now();
954
955 let kernel = self.kernel_registry.two_qubit_kernels.get(gate_name);
957
958 match kernel {
959 Some(k) => match k.kernel_type {
960 TwoQubitKernelType::CNOT => {
961 self.apply_cnot_optimized(state, control, target)?;
962 }
963 TwoQubitKernelType::CZ => {
964 self.apply_cz_optimized(state, control, target)?;
965 }
966 TwoQubitKernelType::SWAP => {
967 self.apply_swap_optimized(state, control, target)?;
968 }
969 TwoQubitKernelType::ISWAP => {
970 self.apply_iswap_optimized(state, control, target)?;
971 }
972 _ => {
973 self.apply_generic_two_qubit(state, control, target, gate_name)?;
974 }
975 },
976 None => {
977 self.apply_generic_two_qubit(state, control, target, gate_name)?;
978 }
979 }
980
981 let mut stats = self
983 .stats
984 .lock()
985 .map_err(|_| QuantRS2Error::InvalidInput("Failed to acquire stats lock".to_string()))?;
986 stats.total_executions += 1;
987 stats.total_execution_time += start.elapsed();
988 *stats
989 .execution_counts
990 .entry(gate_name.to_string())
991 .or_insert(0) += 1;
992
993 Ok(())
994 }
995
996 fn apply_cnot_optimized(
998 &self,
999 state: &mut Array1<Complex64>,
1000 control: usize,
1001 target: usize,
1002 ) -> QuantRS2Result<()> {
1003 let n = state.len();
1004 let control_stride = 1 << control;
1005 let target_stride = 1 << target;
1006
1007 let amplitudes = state.as_slice_mut().ok_or_else(|| {
1008 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
1009 })?;
1010
1011 for i in 0..n {
1013 if (i & control_stride) != 0 {
1014 let partner = i ^ target_stride;
1016 if partner > i {
1017 amplitudes.swap(i, partner);
1018 }
1019 }
1020 }
1021
1022 Ok(())
1023 }
1024
1025 fn apply_cz_optimized(
1027 &self,
1028 state: &mut Array1<Complex64>,
1029 control: usize,
1030 target: usize,
1031 ) -> QuantRS2Result<()> {
1032 let n = state.len();
1033 let control_stride = 1 << control;
1034 let target_stride = 1 << target;
1035
1036 let amplitudes = state.as_slice_mut().ok_or_else(|| {
1037 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
1038 })?;
1039
1040 for (i, amplitude) in amplitudes.iter_mut().enumerate() {
1042 if (i & control_stride) != 0 && (i & target_stride) != 0 {
1043 *amplitude = -*amplitude;
1044 }
1045 }
1046
1047 Ok(())
1048 }
1049
1050 fn apply_swap_optimized(
1052 &self,
1053 state: &mut Array1<Complex64>,
1054 qubit1: usize,
1055 qubit2: usize,
1056 ) -> QuantRS2Result<()> {
1057 let n = state.len();
1058 let stride1 = 1 << qubit1;
1059 let stride2 = 1 << qubit2;
1060
1061 let amplitudes = state.as_slice_mut().ok_or_else(|| {
1062 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
1063 })?;
1064
1065 for i in 0..n {
1067 let bit1 = (i & stride1) != 0;
1068 let bit2 = (i & stride2) != 0;
1069 if bit1 != bit2 {
1070 let partner = i ^ stride1 ^ stride2;
1071 if partner > i {
1072 amplitudes.swap(i, partner);
1073 }
1074 }
1075 }
1076
1077 Ok(())
1078 }
1079
1080 fn apply_iswap_optimized(
1082 &self,
1083 state: &mut Array1<Complex64>,
1084 qubit1: usize,
1085 qubit2: usize,
1086 ) -> QuantRS2Result<()> {
1087 let n = state.len();
1088 let stride1 = 1 << qubit1;
1089 let stride2 = 1 << qubit2;
1090
1091 let amplitudes = state.as_slice_mut().ok_or_else(|| {
1092 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
1093 })?;
1094
1095 for i in 0..n {
1097 let bit1 = (i & stride1) != 0;
1098 let bit2 = (i & stride2) != 0;
1099 if bit1 != bit2 {
1100 let partner = i ^ stride1 ^ stride2;
1101 if partner > i {
1102 let a = amplitudes[i];
1103 let b = amplitudes[partner];
1104 amplitudes[i] = Complex64::new(-b.im, b.re);
1106 amplitudes[partner] = Complex64::new(-a.im, a.re);
1107 }
1108 }
1109 }
1110
1111 Ok(())
1112 }
1113
1114 fn apply_generic_two_qubit(
1124 &self,
1125 state: &mut Array1<Complex64>,
1126 control: usize,
1127 target: usize,
1128 gate_name: &str,
1129 ) -> QuantRS2Result<()> {
1130 let matrix = Self::two_qubit_matrix_for_name(gate_name)?;
1131 Self::apply_matrix4_optimized(state, control, target, &matrix)
1132 }
1133
1134 fn two_qubit_matrix_for_name(gate_name: &str) -> QuantRS2Result<[[Complex64; 4]; 4]> {
1141 let one = Complex64::new(1.0, 0.0);
1142 let zero = Complex64::new(0.0, 0.0);
1143 match gate_name {
1144 "CY" | "cy" => Ok([
1145 [one, zero, zero, zero],
1146 [zero, one, zero, zero],
1147 [zero, zero, zero, Complex64::new(0.0, -1.0)],
1148 [zero, zero, Complex64::new(0.0, 1.0), zero],
1149 ]),
1150 "CH" | "ch" => {
1151 let inv_sqrt2 = Complex64::new(std::f64::consts::FRAC_1_SQRT_2, 0.0);
1152 Ok([
1153 [one, zero, zero, zero],
1154 [zero, one, zero, zero],
1155 [zero, zero, inv_sqrt2, inv_sqrt2],
1156 [zero, zero, inv_sqrt2, -inv_sqrt2],
1157 ])
1158 }
1159 "CS" | "cs" => Ok([
1160 [one, zero, zero, zero],
1161 [zero, one, zero, zero],
1162 [zero, zero, one, zero],
1163 [zero, zero, zero, Complex64::new(0.0, 1.0)],
1164 ]),
1165 _ => Err(QuantRS2Error::UnsupportedOperation(format!(
1166 "gpu_kernel_optimization: no real matrix implementation for two-qubit gate \
1167 '{gate_name}'; add a specialized or generic-matrix case instead of a silent \
1168 no-op"
1169 ))),
1170 }
1171 }
1172
1173 fn apply_matrix4_optimized(
1177 state: &mut Array1<Complex64>,
1178 control: usize,
1179 target: usize,
1180 matrix: &[[Complex64; 4]; 4],
1181 ) -> QuantRS2Result<()> {
1182 let n = state.len();
1183 let control_mask = 1usize << control;
1184 let target_mask = 1usize << target;
1185
1186 let amplitudes = state.as_slice_mut().ok_or_else(|| {
1187 QuantRS2Error::InvalidInput("Failed to get mutable slice".to_string())
1188 })?;
1189
1190 for i in 0..n {
1191 if i & control_mask == 0 && i & target_mask == 0 {
1192 let idx = [
1193 i,
1194 i | target_mask,
1195 i | control_mask,
1196 i | control_mask | target_mask,
1197 ];
1198 let amps = [
1199 amplitudes[idx[0]],
1200 amplitudes[idx[1]],
1201 amplitudes[idx[2]],
1202 amplitudes[idx[3]],
1203 ];
1204 for (row, &out_idx) in idx.iter().enumerate() {
1205 let mut acc = Complex64::new(0.0, 0.0);
1206 for (col, &) in amps.iter().enumerate() {
1207 acc += matrix[row][col] * amp;
1208 }
1209 amplitudes[out_idx] = acc;
1210 }
1211 }
1212 }
1213
1214 Ok(())
1215 }
1216
1217 pub fn get_stats(&self) -> QuantRS2Result<KernelStats> {
1219 let stats = self
1220 .stats
1221 .lock()
1222 .map_err(|_| QuantRS2Error::InvalidInput("Failed to acquire stats lock".to_string()))?;
1223 Ok(stats.clone())
1224 }
1225
1226 pub fn reset_stats(&mut self) -> QuantRS2Result<()> {
1228 let mut stats = self
1229 .stats
1230 .lock()
1231 .map_err(|_| QuantRS2Error::InvalidInput("Failed to acquire stats lock".to_string()))?;
1232 *stats = KernelStats::default();
1233 Ok(())
1234 }
1235
1236 #[must_use]
1238 pub fn get_available_kernels(&self) -> Vec<String> {
1239 let mut kernels = Vec::new();
1240 kernels.extend(self.kernel_registry.single_qubit_kernels.keys().cloned());
1241 kernels.extend(self.kernel_registry.two_qubit_kernels.keys().cloned());
1242 kernels.extend(self.kernel_registry.fused_kernels.keys().cloned());
1243 kernels
1244 }
1245
1246 #[must_use]
1248 pub fn has_kernel(&self, name: &str) -> bool {
1249 self.kernel_registry.single_qubit_kernels.contains_key(name)
1250 || self.kernel_registry.two_qubit_kernels.contains_key(name)
1251 || self.kernel_registry.fused_kernels.contains_key(name)
1252 }
1253}
1254
1255#[cfg(test)]
1256mod tests {
1257 use super::*;
1258
1259 #[test]
1260 fn test_kernel_optimizer_creation() {
1261 let config = GPUKernelConfig::default();
1262 let optimizer = GPUKernelOptimizer::new(config);
1263 assert!(!optimizer.get_available_kernels().is_empty());
1264 }
1265
1266 #[test]
1267 fn test_hadamard_kernel() {
1268 let config = GPUKernelConfig::default();
1269 let mut optimizer = GPUKernelOptimizer::new(config);
1270
1271 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1272
1273 let result = optimizer.apply_single_qubit_gate(&mut state, 0, "hadamard", None);
1274 assert!(result.is_ok());
1275
1276 let inv_sqrt2 = 1.0 / 2.0_f64.sqrt();
1277 assert!((state[0].re - inv_sqrt2).abs() < 1e-10);
1278 assert!((state[1].re - inv_sqrt2).abs() < 1e-10);
1279 }
1280
1281 #[test]
1282 fn test_pauli_x_kernel() {
1283 let config = GPUKernelConfig::default();
1284 let mut optimizer = GPUKernelOptimizer::new(config);
1285
1286 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1287
1288 let result = optimizer.apply_single_qubit_gate(&mut state, 0, "pauli_x", None);
1289 assert!(result.is_ok());
1290
1291 assert!((state[0].re - 0.0).abs() < 1e-10);
1292 assert!((state[1].re - 1.0).abs() < 1e-10);
1293 }
1294
1295 #[test]
1296 fn test_pauli_z_kernel() {
1297 let config = GPUKernelConfig::default();
1298 let mut optimizer = GPUKernelOptimizer::new(config);
1299
1300 let mut state = Array1::from_vec(vec![Complex64::new(0.5, 0.0), Complex64::new(0.5, 0.0)]);
1301
1302 let result = optimizer.apply_single_qubit_gate(&mut state, 0, "pauli_z", None);
1303 assert!(result.is_ok());
1304
1305 assert!((state[0].re - 0.5).abs() < 1e-10);
1306 assert!((state[1].re + 0.5).abs() < 1e-10);
1307 }
1308
1309 #[test]
1310 fn test_rotation_z_kernel() {
1311 let config = GPUKernelConfig::default();
1312 let mut optimizer = GPUKernelOptimizer::new(config);
1313
1314 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1315
1316 let result = optimizer.apply_single_qubit_gate(
1317 &mut state,
1318 0,
1319 "rotation_z",
1320 Some(&[std::f64::consts::PI]),
1321 );
1322 assert!(result.is_ok());
1323 }
1324
1325 #[test]
1326 fn test_cnot_kernel() {
1327 let config = GPUKernelConfig::default();
1328 let mut optimizer = GPUKernelOptimizer::new(config);
1329
1330 let mut state = Array1::from_vec(vec![
1332 Complex64::new(0.0, 0.0),
1333 Complex64::new(0.0, 0.0),
1334 Complex64::new(1.0, 0.0),
1335 Complex64::new(0.0, 0.0),
1336 ]);
1337
1338 let result = optimizer.apply_two_qubit_gate(&mut state, 1, 0, "cnot");
1339 assert!(result.is_ok());
1340
1341 assert!((state[3].re - 1.0).abs() < 1e-10);
1343 }
1344
1345 #[test]
1346 fn test_cz_kernel() {
1347 let config = GPUKernelConfig::default();
1348 let mut optimizer = GPUKernelOptimizer::new(config);
1349
1350 let mut state = Array1::from_vec(vec![
1352 Complex64::new(0.0, 0.0),
1353 Complex64::new(0.0, 0.0),
1354 Complex64::new(0.0, 0.0),
1355 Complex64::new(1.0, 0.0),
1356 ]);
1357
1358 let result = optimizer.apply_two_qubit_gate(&mut state, 1, 0, "cz");
1359 assert!(result.is_ok());
1360
1361 assert!((state[3].re + 1.0).abs() < 1e-10);
1363 }
1364
1365 #[test]
1366 fn test_swap_kernel() {
1367 let config = GPUKernelConfig::default();
1368 let mut optimizer = GPUKernelOptimizer::new(config);
1369
1370 let mut state = Array1::from_vec(vec![
1372 Complex64::new(0.0, 0.0),
1373 Complex64::new(1.0, 0.0),
1374 Complex64::new(0.0, 0.0),
1375 Complex64::new(0.0, 0.0),
1376 ]);
1377
1378 let result = optimizer.apply_two_qubit_gate(&mut state, 0, 1, "swap");
1379 assert!(result.is_ok());
1380
1381 assert!((state[2].re - 1.0).abs() < 1e-10);
1383 }
1384
1385 #[test]
1386 fn test_kernel_stats() {
1387 let config = GPUKernelConfig::default();
1388 let mut optimizer = GPUKernelOptimizer::new(config);
1389
1390 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1391
1392 optimizer
1393 .apply_single_qubit_gate(&mut state, 0, "hadamard", None)
1394 .expect("hadamard gate should apply successfully");
1395 optimizer
1396 .apply_single_qubit_gate(&mut state, 0, "pauli_x", None)
1397 .expect("pauli_x gate should apply successfully");
1398
1399 let stats = optimizer.get_stats().expect("get_stats should succeed");
1400 assert_eq!(stats.total_executions, 2);
1401 assert_eq!(*stats.execution_counts.get("hadamard").unwrap_or(&0), 1);
1402 assert_eq!(*stats.execution_counts.get("pauli_x").unwrap_or(&0), 1);
1403 }
1404
1405 #[test]
1406 fn test_available_kernels() {
1407 let config = GPUKernelConfig::default();
1408 let optimizer = GPUKernelOptimizer::new(config);
1409
1410 let kernels = optimizer.get_available_kernels();
1411 assert!(kernels.contains(&"hadamard".to_string()));
1412 assert!(kernels.contains(&"cnot".to_string()));
1413 assert!(kernels.contains(&"swap".to_string()));
1414 }
1415
1416 #[test]
1417 fn test_has_kernel() {
1418 let config = GPUKernelConfig::default();
1419 let optimizer = GPUKernelOptimizer::new(config);
1420
1421 assert!(optimizer.has_kernel("hadamard"));
1422 assert!(optimizer.has_kernel("cnot"));
1423 assert!(!optimizer.has_kernel("nonexistent"));
1424 }
1425
1426 #[test]
1427 fn test_config_defaults() {
1428 let config = GPUKernelConfig::default();
1429
1430 assert!(config.enable_warp_optimization);
1431 assert!(config.enable_shared_memory);
1432 assert_eq!(config.block_size, 256);
1433 assert!(config.enable_kernel_fusion);
1434 assert_eq!(config.max_fusion_length, 8);
1435 }
1436
1437 #[test]
1438 fn test_reset_stats() {
1439 let config = GPUKernelConfig::default();
1440 let mut optimizer = GPUKernelOptimizer::new(config);
1441
1442 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1443
1444 optimizer
1445 .apply_single_qubit_gate(&mut state, 0, "hadamard", None)
1446 .expect("hadamard gate should apply successfully");
1447 optimizer.reset_stats().expect("reset_stats should succeed");
1448
1449 let stats = optimizer.get_stats().expect("get_stats should succeed");
1450 assert_eq!(stats.total_executions, 0);
1451 }
1452
1453 #[test]
1454 fn test_multiple_qubit_operations() {
1455 let config = GPUKernelConfig::default();
1456 let mut optimizer = GPUKernelOptimizer::new(config);
1457
1458 let mut state = Array1::zeros(8);
1460 state[0] = Complex64::new(1.0, 0.0);
1461
1462 optimizer
1464 .apply_single_qubit_gate(&mut state, 0, "hadamard", None)
1465 .expect("hadamard gate should apply successfully");
1466
1467 optimizer
1469 .apply_two_qubit_gate(&mut state, 0, 1, "cnot")
1470 .expect("cnot gate should apply successfully");
1471
1472 let total_prob: f64 = state.iter().map(|a| (a * a.conj()).re).sum();
1474 assert!((total_prob - 1.0).abs() < 1e-10);
1475 }
1476
1477 #[test]
1484 fn test_generic_single_qubit_applies_real_matrix() {
1485 let config = GPUKernelConfig::default();
1486 let mut optimizer = GPUKernelOptimizer::new(config);
1487
1488 let mut state = Array1::from_vec(vec![Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)]);
1489 optimizer
1490 .apply_single_qubit_gate(&mut state, 0, "S†", None)
1491 .expect("S-dagger gate should apply via the generic path");
1492
1493 assert!((state[0].norm()).abs() < 1e-10);
1494 assert!(
1495 (state[1] - Complex64::new(0.0, -1.0)).norm() < 1e-10,
1496 "expected S† to apply a real -i phase to |1>, got {:?}",
1497 state[1]
1498 );
1499 }
1500
1501 #[test]
1504 fn test_generic_single_qubit_phase_uses_real_angle() {
1505 let config = GPUKernelConfig::default();
1506 let mut optimizer = GPUKernelOptimizer::new(config);
1507
1508 let mut state = Array1::from_vec(vec![Complex64::new(0.0, 0.0), Complex64::new(1.0, 0.0)]);
1509 optimizer
1510 .apply_single_qubit_gate(&mut state, 0, "P", Some(&[std::f64::consts::FRAC_PI_2]))
1511 .expect("P gate should apply via the generic path");
1512
1513 assert!(
1514 (state[1] - Complex64::new(0.0, 1.0)).norm() < 1e-10,
1515 "expected P(pi/2) to apply a real +i phase to |1>, got {:?}",
1516 state[1]
1517 );
1518 }
1519
1520 #[test]
1523 fn test_generic_single_qubit_unknown_name_errors() {
1524 let config = GPUKernelConfig::default();
1525 let mut optimizer = GPUKernelOptimizer::new(config);
1526
1527 let mut state = Array1::from_vec(vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)]);
1528 let result = optimizer.apply_single_qubit_gate(&mut state, 0, "totally_unknown_gate", None);
1529 assert!(
1530 result.is_err(),
1531 "an unresolvable gate name must be an honest error"
1532 );
1533 }
1534
1535 #[test]
1541 fn test_generic_two_qubit_applies_real_matrix() {
1542 let config = GPUKernelConfig::default();
1543 let mut optimizer = GPUKernelOptimizer::new(config);
1544
1545 let mut state = Array1::zeros(4);
1547 state[1] = Complex64::new(1.0, 0.0);
1548
1549 optimizer
1550 .apply_two_qubit_gate(&mut state, 0, 1, "CY")
1551 .expect("CY gate should apply via the generic path");
1552
1553 assert!(state[1].norm() < 1e-10, "amplitude must leave |10>");
1556 assert!(
1557 (state[3] - Complex64::new(0.0, 1.0)).norm() < 1e-10,
1558 "expected CY(control=1) to apply Y with a real +i phase, got {:?}",
1559 state[3]
1560 );
1561 }
1562
1563 #[test]
1567 fn test_generic_two_qubit_unknown_name_errors() {
1568 let config = GPUKernelConfig::default();
1569 let mut optimizer = GPUKernelOptimizer::new(config);
1570
1571 let mut state = Array1::zeros(4);
1572 state[0] = Complex64::new(1.0, 0.0);
1573 let result = optimizer.apply_two_qubit_gate(&mut state, 0, 1, "totally_unknown_gate");
1574 assert!(
1575 result.is_err(),
1576 "an unresolvable gate name must be an honest error"
1577 );
1578 }
1579}