1use crate::{
8 error::{QuantRS2Error, QuantRS2Result},
9 gate::GateOp,
10 qubit::QubitId,
11};
12use scirs2_core::Complex64;
13use std::collections::HashMap;
14use std::sync::{Arc, Mutex};
15
16#[cfg(feature = "gpu")]
18fn map_cuda_err(err: oxicuda::CudaError) -> QuantRS2Error {
19 QuantRS2Error::BackendExecutionFailed(format!("OxiCUDA driver error: {err:?}"))
20}
21
22fn uncompiled_kernel_err(name: &str) -> QuantRS2Error {
24 QuantRS2Error::UnsupportedOperation(format!(
25 "specialized CUDA kernel `{name}` is not available: real PTX device code has not been \
26 authored yet (no fabricated kernel is returned)"
27 ))
28}
29
30fn uncompiled_shader_err(name: &str) -> QuantRS2Error {
32 QuantRS2Error::UnsupportedOperation(format!(
33 "specialized WebGPU shader `{name}` is not available: real WGSL device code has not been \
34 authored yet (no fabricated shader is returned)"
35 ))
36}
37
38#[cfg(feature = "gpu")]
44fn query_webgpu_limits() -> QuantRS2Result<WebGpuLimits> {
45 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
47 let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
48 power_preference: wgpu::PowerPreference::HighPerformance,
49 force_fallback_adapter: false,
50 compatible_surface: None,
51 ..Default::default()
56 }))
57 .map_err(|e| {
58 QuantRS2Error::BackendExecutionFailed(format!("no WebGPU adapter available: {e}"))
59 })?;
60
61 let limits = adapter.limits();
62 Ok(WebGpuLimits {
63 max_compute_workgroup_size: limits.max_compute_workgroup_size_x,
64 })
65}
66
67fn apply_dense_gate_cpu(
78 state: &mut [Complex64],
79 matrix: &[Complex64],
80 target_qubits: &[QubitId],
81) -> QuantRS2Result<()> {
82 let state_len = state.len();
83 if state_len == 0 || !state_len.is_power_of_two() {
84 return Err(QuantRS2Error::InvalidInput(format!(
85 "state vector length must be a non-zero power of two, got {state_len}"
86 )));
87 }
88 let n_qubits = state_len.trailing_zeros() as usize;
89
90 let gate_qubits = target_qubits.len();
91 if gate_qubits == 0 {
92 return Err(QuantRS2Error::InvalidInput(
93 "holonomic/dense gate requires at least one target qubit".to_string(),
94 ));
95 }
96 if gate_qubits > n_qubits {
97 return Err(QuantRS2Error::InvalidInput(format!(
98 "gate acts on {gate_qubits} qubits but the state only has {n_qubits}"
99 )));
100 }
101
102 let gate_dim = 1usize << gate_qubits;
103 if matrix.len() != gate_dim * gate_dim {
104 return Err(QuantRS2Error::InvalidInput(format!(
105 "gate matrix has {} entries but a {gate_dim}x{gate_dim} ({}) matrix was expected",
106 matrix.len(),
107 gate_dim * gate_dim
108 )));
109 }
110
111 let mut qubit_indices: Vec<usize> = target_qubits.iter().map(|q| q.0 as usize).collect();
113 qubit_indices.sort_unstable();
114 for &idx in &qubit_indices {
115 if idx >= n_qubits {
116 return Err(QuantRS2Error::InvalidInput(format!(
117 "target qubit {idx} out of range for a {n_qubits}-qubit state"
118 )));
119 }
120 }
121 qubit_indices.dedup();
122 if qubit_indices.len() != gate_qubits {
123 return Err(QuantRS2Error::InvalidInput(
124 "duplicate target qubits supplied to dense gate".to_string(),
125 ));
126 }
127
128 let unaffected_qubits = n_qubits - gate_qubits;
129 let iterations = 1usize << unaffected_qubits;
130
131 let mut indices = vec![0usize; gate_dim];
132 let mut temp = vec![Complex64::new(0.0, 0.0); gate_dim];
133
134 for i in 0..iterations {
135 let mut base = 0usize;
138 let mut remaining = i;
139 let mut qubit_pos = 0usize;
140 for bit in 0..n_qubits {
141 if qubit_pos < gate_qubits && bit == qubit_indices[qubit_pos] {
142 qubit_pos += 1;
143 } else {
144 if remaining & 1 == 1 {
145 base |= 1 << bit;
146 }
147 remaining >>= 1;
148 }
149 }
150
151 for (j, slot) in indices.iter_mut().enumerate() {
153 let mut idx = base;
154 for (k, &qubit_idx) in qubit_indices.iter().enumerate() {
155 if (j >> k) & 1 == 1 {
156 idx |= 1 << qubit_idx;
157 }
158 }
159 *slot = idx;
160 }
161
162 for (t, &idx) in indices.iter().enumerate() {
164 temp[t] = state[idx];
165 }
166 for (row, &idx) in indices.iter().enumerate() {
167 let mut sum = Complex64::new(0.0, 0.0);
168 let row_off = row * gate_dim;
169 for (col, &) in temp.iter().enumerate() {
170 sum += matrix[row_off + col] * amp;
171 }
172 state[idx] = sum;
173 }
174 }
175
176 Ok(())
177}
178
179pub struct SpecializedGpuKernels {
181 cuda_context: Option<CudaSpecializedContext>,
183 webgpu_context: Option<WebGpuSpecializedContext>,
185 kernel_cache: Arc<Mutex<KernelCache>>,
187 performance_stats: Arc<Mutex<PerformanceStats>>,
189 config: OptimizationConfig,
191}
192
193pub struct CudaSpecializedContext {
195 #[allow(dead_code)]
197 compute_capability: (i32, i32),
198 has_tensor_cores: bool,
200 #[allow(dead_code)]
202 max_shared_memory: usize,
203 #[allow(dead_code)]
205 warp_size: usize,
206 kernels: HashMap<String, CompiledKernel>,
208}
209
210pub struct WebGpuSpecializedContext {
212 #[allow(dead_code)]
214 device_limits: WebGpuLimits,
215 #[allow(dead_code)]
217 shaders: HashMap<String, CompiledShader>,
218 #[allow(dead_code)]
220 buffer_pools: HashMap<String, BufferPool>,
221}
222
223pub struct KernelCache {
225 #[allow(dead_code)]
227 cuda_kernels: HashMap<String, CachedCudaKernel>,
228 #[allow(dead_code)]
230 webgpu_shaders: HashMap<String, CachedWebGpuShader>,
231 cache_stats: CacheStatistics,
233}
234
235pub struct PerformanceStats {
237 kernel_times: HashMap<String, Vec<f64>>,
239 memory_bandwidth: HashMap<String, f64>,
241 tensor_core_utilization: f64,
243 #[allow(dead_code)]
245 cache_hit_rates: HashMap<String, f64>,
246}
247
248#[derive(Debug, Clone)]
250pub struct OptimizationConfig {
251 pub use_tensor_cores: bool,
253 pub optimize_memory_access: bool,
255 pub enable_gate_fusion: bool,
257 pub max_fusion_length: usize,
259 pub coalescing_threshold: usize,
261 pub use_mixed_precision: bool,
263}
264
265impl Default for OptimizationConfig {
266 fn default() -> Self {
267 Self {
268 use_tensor_cores: true,
269 optimize_memory_access: true,
270 enable_gate_fusion: true,
271 max_fusion_length: 8,
272 coalescing_threshold: 32,
273 use_mixed_precision: true,
274 }
275 }
276}
277
278impl SpecializedGpuKernels {
279 pub fn new(config: OptimizationConfig) -> QuantRS2Result<Self> {
281 let cuda_context = Self::initialize_cuda_context(&config)?;
282 let webgpu_context = Self::initialize_webgpu_context(&config)?;
283
284 Ok(Self {
285 cuda_context,
286 webgpu_context,
287 kernel_cache: Arc::new(Mutex::new(KernelCache::new())),
288 performance_stats: Arc::new(Mutex::new(PerformanceStats::new())),
289 config,
290 })
291 }
292
293 fn initialize_cuda_context(
302 config: &OptimizationConfig,
303 ) -> QuantRS2Result<Option<CudaSpecializedContext>> {
304 if !Self::is_cuda_available() {
306 return Ok(None);
307 }
308
309 let compute_capability = Self::get_compute_capability()?;
311 let has_tensor_cores = compute_capability.0 >= 7; let device_props = Self::get_device_properties()?;
313
314 let kernel_specs: [(
319 &str,
320 fn(&OptimizationConfig) -> QuantRS2Result<CompiledKernel>,
321 ); 5] = [
322 ("holonomic_gate", Self::compile_holonomic_kernel),
323 ("post_quantum_hash", Self::compile_post_quantum_kernel),
324 ("quantum_ml_attention", Self::compile_qml_attention_kernel),
325 (
326 "fused_rotation_sequence",
327 Self::compile_fused_rotation_kernel,
328 ),
329 ("tensor_core_matmul", Self::compile_tensor_core_kernel),
330 ];
331
332 let mut kernels = HashMap::with_capacity(kernel_specs.len());
333 for (name, compile) in kernel_specs {
334 match compile(config) {
335 Ok(kernel) => {
336 kernels.insert(name.to_string(), kernel);
337 }
338 Err(_) => return Ok(None),
340 }
341 }
342
343 Ok(Some(CudaSpecializedContext {
344 compute_capability,
345 has_tensor_cores,
346 max_shared_memory: device_props.max_shared_memory,
347 warp_size: device_props.warp_size,
348 kernels,
349 }))
350 }
351
352 fn initialize_webgpu_context(
360 config: &OptimizationConfig,
361 ) -> QuantRS2Result<Option<WebGpuSpecializedContext>> {
362 let device_limits = match Self::get_webgpu_limits() {
364 Ok(limits) => limits,
365 Err(_) => return Ok(None),
366 };
367
368 let shader_specs: [(
369 &str,
370 fn(&OptimizationConfig) -> QuantRS2Result<CompiledShader>,
371 ); 3] = [
372 ("holonomic_gate", Self::compile_holonomic_shader),
373 ("post_quantum_hash", Self::compile_post_quantum_shader),
374 ("quantum_ml_attention", Self::compile_qml_attention_shader),
375 ];
376
377 let mut shaders = HashMap::with_capacity(shader_specs.len());
378 for (name, compile) in shader_specs {
379 match compile(config) {
380 Ok(shader) => {
381 shaders.insert(name.to_string(), shader);
382 }
383 Err(_) => return Ok(None),
385 }
386 }
387
388 let mut buffer_pools = HashMap::new();
389 buffer_pools.insert("state_vectors".to_string(), BufferPool::new(1024 * 1024)); buffer_pools.insert("gate_matrices".to_string(), BufferPool::new(512 * 1024)); buffer_pools.insert("temporary_buffers".to_string(), BufferPool::new(256 * 1024)); Ok(Some(WebGpuSpecializedContext {
394 device_limits,
395 shaders,
396 buffer_pools,
397 }))
398 }
399
400 pub fn apply_holonomic_gate(
409 &self,
410 state: &mut [Complex64],
411 holonomy_matrix: &[Complex64],
412 target_qubits: &[QubitId],
413 ) -> QuantRS2Result<()> {
414 let state_size = state.len();
415
416 if state_size > 1024 && self.cuda_context.is_some() {
418 self.apply_holonomic_gate_cuda(state, holonomy_matrix, target_qubits)
419 } else if self.webgpu_context.is_some() {
420 self.apply_holonomic_gate_webgpu(state, holonomy_matrix, target_qubits)
421 } else {
422 apply_dense_gate_cpu(state, holonomy_matrix, target_qubits)
424 }
425 }
426
427 fn apply_holonomic_gate_cuda(
434 &self,
435 _state: &mut [Complex64],
436 _holonomy_matrix: &[Complex64],
437 _target_qubits: &[QubitId],
438 ) -> QuantRS2Result<()> {
439 Err(uncompiled_kernel_err("holonomic_gate"))
440 }
441
442 pub fn apply_post_quantum_hash_gate(
450 &self,
451 _state: &mut [Complex64],
452 _hash_circuit: &[Complex64],
453 compression_type: PostQuantumCompressionType,
454 ) -> QuantRS2Result<()> {
455 let scheme = match compression_type {
456 PostQuantumCompressionType::QuantumSponge { .. } => "quantum_sponge",
457 PostQuantumCompressionType::QuantumMerkleTree { .. } => "quantum_merkle_tree",
458 PostQuantumCompressionType::QuantumGrover { .. } => "quantum_grover",
459 };
460 Err(QuantRS2Error::UnsupportedOperation(format!(
461 "post-quantum hash gate `{scheme}` is not implemented: the GPU kernel is DEFERRED and \
462 there is no CPU reference (refusing to fabricate a no-op success)"
463 )))
464 }
465
466 pub fn apply_quantum_ml_attention(
473 &self,
474 _state: &mut [Complex64],
475 _query_params: &[Complex64],
476 _key_params: &[Complex64],
477 _value_params: &[Complex64],
478 _num_heads: usize,
479 ) -> QuantRS2Result<()> {
480 Err(QuantRS2Error::UnsupportedOperation(
481 "quantum ML attention is not implemented: the specialized GPU kernels are DEFERRED and \
482 there is no CPU reference (refusing to fabricate a no-op success)"
483 .to_string(),
484 ))
485 }
486
487 pub fn apply_fused_gate_sequence(
496 &self,
497 state: &mut [Complex64],
498 gates: &[Box<dyn GateOp>],
499 ) -> QuantRS2Result<()> {
500 let fusion_chains = if self.config.enable_gate_fusion && gates.len() >= 2 {
502 self.analyze_gate_fusion_opportunities(gates)?
503 } else {
504 Vec::new()
505 };
506
507 if fusion_chains.is_empty() {
508 for gate in gates {
510 self.apply_single_gate_optimized(state, gate.as_ref())?;
511 }
512 return Ok(());
513 }
514
515 for chain in fusion_chains {
518 for gate in &chain.gates {
519 self.apply_single_gate_optimized(state, gate.as_ref())?;
520 }
521 }
522
523 Ok(())
524 }
525
526 fn update_performance_stats(&self, kernel_name: &str, execution_time: f64) {
531 if let Ok(mut stats) = self.performance_stats.lock() {
532 stats
533 .kernel_times
534 .entry(kernel_name.to_string())
535 .or_default()
536 .push(execution_time);
537 }
538 }
540
541 pub fn get_performance_report(&self) -> PerformanceReport {
543 let stats = self
544 .performance_stats
545 .lock()
546 .unwrap_or_else(|e| e.into_inner());
547 let cache = self.kernel_cache.lock().unwrap_or_else(|e| e.into_inner());
548
549 PerformanceReport {
550 average_kernel_times: stats
551 .kernel_times
552 .iter()
553 .map(|(k, v)| (k.clone(), v.iter().sum::<f64>() / v.len() as f64))
554 .collect(),
555 cache_hit_rate: cache.cache_stats.overall_hit_rate(),
556 tensor_core_utilization: stats.tensor_core_utilization,
557 memory_bandwidth_utilization: stats.memory_bandwidth.values().sum::<f64>()
558 / stats.memory_bandwidth.len() as f64,
559 }
560 }
561
562 fn is_cuda_available() -> bool {
569 crate::gpu::is_gpu_available()
570 }
571
572 fn get_compute_capability() -> QuantRS2Result<(i32, i32)> {
578 #[cfg(feature = "gpu")]
579 {
580 oxicuda::init().map_err(map_cuda_err)?;
581 let device = oxicuda::Device::get(0).map_err(map_cuda_err)?;
582 device.compute_capability().map_err(map_cuda_err)
583 }
584 #[cfg(not(feature = "gpu"))]
585 {
586 Err(crate::error::QuantRS2Error::UnsupportedOperation(
587 "compute capability unavailable: GPU backend not linked (enable the `gpu` feature)"
588 .to_string(),
589 ))
590 }
591 }
592
593 fn get_device_properties() -> QuantRS2Result<DeviceProperties> {
598 #[cfg(feature = "gpu")]
599 {
600 oxicuda::init().map_err(map_cuda_err)?;
601 let device = oxicuda::Device::get(0).map_err(map_cuda_err)?;
602 let warp_size = device.warp_size().map_err(map_cuda_err)? as usize;
603 let max_shared_memory =
604 device.max_shared_memory_per_block().map_err(map_cuda_err)? as usize;
605 Ok(DeviceProperties {
606 max_shared_memory,
607 warp_size,
608 })
609 }
610 #[cfg(not(feature = "gpu"))]
611 {
612 Err(crate::error::QuantRS2Error::UnsupportedOperation(
613 "device properties unavailable: GPU backend not linked (enable the `gpu` feature)"
614 .to_string(),
615 ))
616 }
617 }
618
619 fn get_webgpu_limits() -> QuantRS2Result<WebGpuLimits> {
625 #[cfg(feature = "gpu")]
626 {
627 query_webgpu_limits()
628 }
629 #[cfg(not(feature = "gpu"))]
630 {
631 Err(crate::error::QuantRS2Error::UnsupportedOperation(
632 "WebGPU limits unavailable: GPU backend not linked (enable the `gpu` feature)"
633 .to_string(),
634 ))
635 }
636 }
637
638 fn compile_holonomic_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
647 Err(uncompiled_kernel_err("holonomic_gate"))
648 }
649 fn compile_post_quantum_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
650 Err(uncompiled_kernel_err("post_quantum_hash"))
651 }
652 fn compile_qml_attention_kernel(
653 _config: &OptimizationConfig,
654 ) -> QuantRS2Result<CompiledKernel> {
655 Err(uncompiled_kernel_err("quantum_ml_attention"))
656 }
657 fn compile_fused_rotation_kernel(
658 _config: &OptimizationConfig,
659 ) -> QuantRS2Result<CompiledKernel> {
660 Err(uncompiled_kernel_err("fused_rotation_sequence"))
661 }
662 fn compile_tensor_core_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
663 Err(uncompiled_kernel_err("tensor_core_matmul"))
664 }
665
666 fn compile_holonomic_shader(_config: &OptimizationConfig) -> QuantRS2Result<CompiledShader> {
667 Err(uncompiled_shader_err("holonomic_gate"))
668 }
669 fn compile_post_quantum_shader(_config: &OptimizationConfig) -> QuantRS2Result<CompiledShader> {
670 Err(uncompiled_shader_err("post_quantum_hash"))
671 }
672 fn compile_qml_attention_shader(
673 _config: &OptimizationConfig,
674 ) -> QuantRS2Result<CompiledShader> {
675 Err(uncompiled_shader_err("quantum_ml_attention"))
676 }
677
678 fn apply_holonomic_gate_webgpu(
684 &self,
685 _state: &mut [Complex64],
686 _matrix: &[Complex64],
687 _qubits: &[QubitId],
688 ) -> QuantRS2Result<()> {
689 Err(uncompiled_shader_err("holonomic_gate"))
690 }
691
692 fn apply_single_gate_optimized(
698 &self,
699 state: &mut [Complex64],
700 gate: &dyn GateOp,
701 ) -> QuantRS2Result<()> {
702 let matrix = gate.matrix()?;
703 let qubits = gate.qubits();
704 apply_dense_gate_cpu(state, &matrix, &qubits)
705 }
706
707 fn analyze_gate_fusion_opportunities(
715 &self,
716 _gates: &[Box<dyn GateOp>],
717 ) -> QuantRS2Result<Vec<FusionChain>> {
718 Ok(Vec::new())
719 }
720}
721
722#[derive(Debug, Clone)]
725pub enum PostQuantumCompressionType {
726 QuantumSponge { rate: usize, capacity: usize },
727 QuantumMerkleTree { depth: usize, arity: usize },
728 QuantumGrover { iterations: usize },
729}
730
731#[derive(Debug, Clone)]
732pub enum FusionType {
733 RotationSequence,
734 PauliString,
735 ControlledSequence,
736 None,
737}
738
739pub struct FusionChain {
740 pub gates: Vec<Box<dyn GateOp>>,
741 pub fusion_type: FusionType,
742}
743
744pub struct CompiledKernel {
745 pub name: String,
746 pub last_execution_time: f64,
747}
748
749pub struct CompiledShader {
750 pub name: String,
751}
752
753pub struct CachedCudaKernel {
754 pub kernel: CompiledKernel,
755 pub compilation_time: f64,
756}
757
758pub struct CachedWebGpuShader {
759 pub shader: CompiledShader,
760 pub compilation_time: f64,
761}
762
763pub struct CacheStatistics {
764 pub hits: usize,
765 pub misses: usize,
766}
767
768impl CacheStatistics {
769 pub fn overall_hit_rate(&self) -> f64 {
770 if self.hits + self.misses == 0 {
771 0.0
772 } else {
773 self.hits as f64 / (self.hits + self.misses) as f64
774 }
775 }
776}
777
778pub struct BufferPool {
779 pub initial_size: usize,
780}
781
782impl BufferPool {
783 pub const fn new(initial_size: usize) -> Self {
784 Self { initial_size }
785 }
786}
787
788pub struct DeviceProperties {
789 pub max_shared_memory: usize,
790 pub warp_size: usize,
791}
792
793pub struct WebGpuLimits {
794 pub max_compute_workgroup_size: u32,
795}
796
797pub struct PerformanceReport {
798 pub average_kernel_times: HashMap<String, f64>,
799 pub cache_hit_rate: f64,
800 pub tensor_core_utilization: f64,
801 pub memory_bandwidth_utilization: f64,
802}
803
804impl KernelCache {
805 pub fn new() -> Self {
806 Self {
807 cuda_kernels: HashMap::new(),
808 webgpu_shaders: HashMap::new(),
809 cache_stats: CacheStatistics { hits: 0, misses: 0 },
810 }
811 }
812}
813
814impl Default for KernelCache {
815 fn default() -> Self {
816 Self::new()
817 }
818}
819
820impl PerformanceStats {
821 pub fn new() -> Self {
822 Self {
823 kernel_times: HashMap::new(),
824 memory_bandwidth: HashMap::new(),
825 tensor_core_utilization: 0.0,
826 cache_hit_rates: HashMap::new(),
827 }
828 }
829}
830
831impl Default for PerformanceStats {
832 fn default() -> Self {
833 Self::new()
834 }
835}
836
837#[cfg(test)]
838mod tests {
839 use super::*;
840 use std::f64::consts::FRAC_1_SQRT_2;
841
842 #[test]
843 fn test_specialized_gpu_kernels_creation() {
844 let config = OptimizationConfig::default();
845 let kernels = SpecializedGpuKernels::new(config);
846 assert!(kernels.is_ok());
847 }
848
849 #[test]
850 fn test_holonomic_identity_preserves_state() {
851 let config = OptimizationConfig::default();
852 let kernels =
853 SpecializedGpuKernels::new(config).expect("Failed to create specialized GPU kernels");
854
855 let mut state = vec![
856 Complex64::new(0.6, 0.0),
857 Complex64::new(0.0, 0.8),
858 Complex64::new(0.0, 0.0),
859 Complex64::new(0.0, 0.0),
860 ];
861 let original = state.clone();
862 let identity = vec![
864 Complex64::new(1.0, 0.0),
865 Complex64::new(0.0, 0.0),
866 Complex64::new(0.0, 0.0),
867 Complex64::new(1.0, 0.0),
868 ];
869 kernels
870 .apply_holonomic_gate(&mut state, &identity, &[QubitId(0)])
871 .expect("identity holonomic gate should succeed");
872
873 for (a, b) in state.iter().zip(original.iter()) {
874 assert!((a - b).norm() < 1e-12, "identity must not change the state");
875 }
876 }
877
878 #[test]
879 fn test_holonomic_gate_is_real_not_noop() {
880 let config = OptimizationConfig::default();
883 let kernels =
884 SpecializedGpuKernels::new(config).expect("Failed to create specialized GPU kernels");
885
886 let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
887 let h = vec![
888 Complex64::new(FRAC_1_SQRT_2, 0.0),
889 Complex64::new(FRAC_1_SQRT_2, 0.0),
890 Complex64::new(FRAC_1_SQRT_2, 0.0),
891 Complex64::new(-FRAC_1_SQRT_2, 0.0),
892 ];
893 kernels
894 .apply_holonomic_gate(&mut state, &h, &[QubitId(0)])
895 .expect("hadamard holonomic gate should succeed");
896
897 assert!((state[0].re - FRAC_1_SQRT_2).abs() < 1e-12);
899 assert!((state[1].re - FRAC_1_SQRT_2).abs() < 1e-12);
900 assert!(
901 (state[1].norm() - FRAC_1_SQRT_2).abs() < 1e-12,
902 "second amplitude must be populated; a no-op would leave it at 0"
903 );
904 }
905
906 #[test]
907 fn test_dense_gate_on_high_qubit_index() {
908 let mut state = vec![
911 Complex64::new(1.0, 0.0),
912 Complex64::new(0.0, 0.0),
913 Complex64::new(0.0, 0.0),
914 Complex64::new(0.0, 0.0),
915 ];
916 let x = vec![
917 Complex64::new(0.0, 0.0),
918 Complex64::new(1.0, 0.0),
919 Complex64::new(1.0, 0.0),
920 Complex64::new(0.0, 0.0),
921 ];
922 apply_dense_gate_cpu(&mut state, &x, &[QubitId(1)]).expect("X on qubit 1 should succeed");
923 assert!(
924 (state[2].re - 1.0).abs() < 1e-12,
925 "amplitude should move to index 2"
926 );
927 assert!(state[0].norm() < 1e-12);
928 }
929
930 #[test]
931 fn test_dense_gate_dimension_mismatch_errors() {
932 let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
933 let bad = vec![Complex64::new(1.0, 0.0); 3];
935 assert!(apply_dense_gate_cpu(&mut state, &bad, &[QubitId(0)]).is_err());
936 }
937
938 #[test]
939 fn test_post_quantum_and_attention_are_honest_errors() {
940 let kernels = SpecializedGpuKernels::new(OptimizationConfig::default())
943 .expect("kernel manager creation");
944 let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
945
946 let pq = kernels.apply_post_quantum_hash_gate(
947 &mut state,
948 &[Complex64::new(1.0, 0.0)],
949 PostQuantumCompressionType::QuantumGrover { iterations: 1 },
950 );
951 assert!(
952 pq.is_err(),
953 "post-quantum hash gate must be an honest error"
954 );
955
956 let att = kernels.apply_quantum_ml_attention(
957 &mut state,
958 &[Complex64::new(1.0, 0.0)],
959 &[Complex64::new(1.0, 0.0)],
960 &[Complex64::new(1.0, 0.0)],
961 1,
962 );
963 assert!(att.is_err(), "quantum ML attention must be an honest error");
964 }
965
966 #[test]
967 fn test_compute_capability_is_not_hardcoded_75() {
968 match SpecializedGpuKernels::get_compute_capability() {
972 Ok(cc) => {
973 assert_ne!(
974 cc,
975 (7, 5),
976 "compute capability must be a real probe, not the fabricated (7,5)"
977 );
978 assert!(cc.0 >= 1, "real compute capability major must be >= 1");
979 }
980 Err(_) => {
981 }
983 }
984 }
985
986 #[test]
987 fn test_performance_reporting() {
988 let config = OptimizationConfig::default();
989 let kernels = SpecializedGpuKernels::new(config)
990 .expect("Failed to create specialized GPU kernels for performance reporting");
991
992 let report = kernels.get_performance_report();
993 assert!(report.cache_hit_rate >= 0.0 && report.cache_hit_rate <= 1.0);
994 }
995}