1use crate::error::{QuantRS2Error, QuantRS2Result};
7use crate::gpu::large_scale_simulation::GpuBackend;
8use crate::gpu::{GpuBackend as QuantumGpuBackend, GpuBuffer, GpuKernel};
9use crate::gpu_stubs::SciRS2GpuConfig;
10use scirs2_core::Complex64;
11use std::collections::HashMap;
12use std::sync::{Arc, Mutex};
13
14#[cfg(feature = "gpu")]
15type GpuDevice = ();
18#[derive(Debug, Clone)]
54pub struct SciRS2GpuMetrics {
55 pub kernel_executions: usize,
57 pub avg_kernel_time_us: f64,
59 pub memory_bandwidth_utilization: f64,
61 pub compute_utilization: f64,
63 pub cache_hit_rate: f64,
65 pub memory_usage_bytes: usize,
67}
68
69pub struct SciRS2BufferAdapter {
71 size: usize,
73 #[cfg(feature = "gpu")]
75 device: Option<Arc<GpuDevice>>,
76 data: Vec<Complex64>,
78 config: SciRS2GpuConfig,
80 metrics: Arc<Mutex<SciRS2GpuMetrics>>,
82}
83
84impl SciRS2BufferAdapter {
85 pub fn new(size: usize) -> Self {
87 Self::with_config(size, SciRS2GpuConfig::default())
88 }
89
90 pub fn with_config(size: usize, config: SciRS2GpuConfig) -> Self {
92 let metrics = Arc::new(Mutex::new(SciRS2GpuMetrics {
93 kernel_executions: 0,
94 avg_kernel_time_us: 0.0,
95 memory_bandwidth_utilization: 0.0,
96 compute_utilization: 0.0,
97 cache_hit_rate: 0.0,
98 memory_usage_bytes: size * std::mem::size_of::<Complex64>(),
99 }));
100
101 Self {
102 size,
103 #[cfg(feature = "gpu")]
104 device: None,
105 data: vec![Complex64::new(0.0, 0.0); size],
106 config,
107 metrics,
108 }
109 }
110
111 #[cfg(feature = "gpu")]
113 pub fn initialize_gpu(&mut self) -> QuantRS2Result<()> {
114 match get_scirs2_gpu_device() {
115 Ok(device) => {
116 self.device = Some(Arc::new(device));
117 Ok(())
118 }
119 Err(e) => {
120 eprintln!("GPU initialization failed, falling back to CPU: {}", e);
122 Ok(())
123 }
124 }
125 }
126
127 pub fn get_metrics(&self) -> SciRS2GpuMetrics {
129 if let Ok(metrics) = self.metrics.lock() {
130 metrics.clone()
131 } else {
132 SciRS2GpuMetrics {
133 kernel_executions: 0,
134 avg_kernel_time_us: 0.0,
135 memory_bandwidth_utilization: 0.0,
136 compute_utilization: 0.0,
137 cache_hit_rate: 0.0,
138 memory_usage_bytes: self.size * std::mem::size_of::<Complex64>(),
139 }
140 }
141 }
142
143 #[cfg(feature = "gpu")]
145 pub fn is_gpu_active(&self) -> bool {
146 self.device.is_some()
147 }
148
149 #[cfg(not(feature = "gpu"))]
150 pub fn is_gpu_active(&self) -> bool {
151 false
152 }
153}
154
155impl GpuBuffer for SciRS2BufferAdapter {
156 fn size(&self) -> usize {
157 self.size * std::mem::size_of::<Complex64>()
158 }
159
160 fn upload(&mut self, data: &[Complex64]) -> QuantRS2Result<()> {
161 if data.len() != self.size {
162 return Err(QuantRS2Error::InvalidInput(format!(
163 "Data size {} doesn't match buffer size {}",
164 data.len(),
165 self.size
166 )));
167 }
168
169 #[cfg(feature = "gpu")]
170 if let Some(ref _device) = self.device {
171 self.data.copy_from_slice(data);
174
175 if let Ok(mut metrics) = self.metrics.lock() {
177 metrics.memory_usage_bytes = self.size * std::mem::size_of::<Complex64>();
178 }
179
180 return Ok(());
181 }
182
183 self.data.copy_from_slice(data);
185 Ok(())
186 }
187
188 fn download(&self, data: &mut [Complex64]) -> QuantRS2Result<()> {
189 if data.len() != self.size {
190 return Err(QuantRS2Error::InvalidInput(format!(
191 "Data size {} doesn't match buffer size {}",
192 data.len(),
193 self.size
194 )));
195 }
196
197 #[cfg(feature = "gpu")]
198 if let Some(ref _device) = self.device {
199 data.copy_from_slice(&self.data);
202 return Ok(());
203 }
204
205 data.copy_from_slice(&self.data);
207 Ok(())
208 }
209
210 fn sync(&self) -> QuantRS2Result<()> {
211 #[cfg(feature = "gpu")]
212 if let Some(ref _device) = self.device {
213 return Ok(());
216 }
217
218 Ok(())
220 }
221
222 fn as_any(&self) -> &dyn std::any::Any {
223 self
224 }
225
226 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
227 self
228 }
229}
230
231pub struct SciRS2KernelAdapter {
233 config: SciRS2GpuConfig,
235 kernel_cache: HashMap<String, String>,
237 metrics: Arc<Mutex<SciRS2GpuMetrics>>,
239 #[cfg(feature = "gpu")]
241 device: Option<Arc<GpuDevice>>,
242}
243
244impl SciRS2KernelAdapter {
245 pub fn new() -> Self {
247 Self::with_config(SciRS2GpuConfig::default())
248 }
249
250 pub fn with_config(config: SciRS2GpuConfig) -> Self {
252 let metrics = Arc::new(Mutex::new(SciRS2GpuMetrics {
253 kernel_executions: 0,
254 avg_kernel_time_us: 0.0,
255 memory_bandwidth_utilization: 0.8, compute_utilization: 0.7, cache_hit_rate: 0.9, memory_usage_bytes: 0,
259 }));
260
261 Self {
262 config,
263 kernel_cache: HashMap::new(),
264 metrics,
265 #[cfg(feature = "gpu")]
266 device: None,
267 }
268 }
269
270 #[cfg(feature = "gpu")]
272 pub fn initialize_gpu(&mut self) -> QuantRS2Result<()> {
273 match get_scirs2_gpu_device() {
274 Ok(device) => {
275 self.device = Some(Arc::new(device));
276 Ok(())
277 }
278 Err(e) => {
279 eprintln!("GPU initialization failed, using CPU fallback: {}", e);
280 Ok(())
281 }
282 }
283 }
284
285 fn compile_kernel(&mut self, kernel_name: &str, kernel_source: &str) -> QuantRS2Result<()> {
287 if self.config.enable_kernel_cache {
288 self.kernel_cache
289 .insert(kernel_name.to_string(), kernel_source.to_string());
290 }
291
292 Ok(())
295 }
296
297 fn execute_single_qubit_kernel(
299 &self,
300 state: &mut dyn GpuBuffer,
301 gate_matrix: &[Complex64; 4],
302 qubit: crate::qubit::QubitId,
303 n_qubits: usize,
304 ) -> QuantRS2Result<()> {
305 use std::time::Instant;
306 let start = Instant::now();
307
308 let buffer = state
310 .as_any_mut()
311 .downcast_mut::<SciRS2BufferAdapter>()
312 .ok_or_else(|| QuantRS2Error::InvalidInput("Invalid buffer type".to_string()))?;
313
314 let size = 1 << n_qubits;
315 let qubit_idx = qubit.0;
316 let target_bit = 1 << qubit_idx;
317
318 for i in 0..size {
320 if i & target_bit == 0 {
321 let j = i | target_bit;
322 let amp_0 = buffer.data[i];
323 let amp_1 = buffer.data[j];
324
325 buffer.data[i] = gate_matrix[0] * amp_0 + gate_matrix[1] * amp_1;
326 buffer.data[j] = gate_matrix[2] * amp_0 + gate_matrix[3] * amp_1;
327 }
328 }
329
330 if let Ok(mut metrics) = self.metrics.lock() {
332 metrics.kernel_executions += 1;
333 let duration = start.elapsed();
334 let duration_us = duration.as_nanos() as f64 / 1000.0;
335
336 let alpha = 0.1;
338 metrics.avg_kernel_time_us =
339 alpha * duration_us + (1.0 - alpha) * metrics.avg_kernel_time_us;
340 }
341
342 Ok(())
343 }
344
345 fn execute_two_qubit_kernel(
347 &self,
348 state: &mut dyn GpuBuffer,
349 gate_matrix: &[Complex64; 16],
350 control: crate::qubit::QubitId,
351 target: crate::qubit::QubitId,
352 n_qubits: usize,
353 ) -> QuantRS2Result<()> {
354 use std::time::Instant;
355 let start = Instant::now();
356
357 let buffer = state
358 .as_any_mut()
359 .downcast_mut::<SciRS2BufferAdapter>()
360 .ok_or_else(|| QuantRS2Error::InvalidInput("Invalid buffer type".to_string()))?;
361
362 let size = 1 << n_qubits;
363 let control_bit = 1 << control.0;
364 let target_bit = 1 << target.0;
365
366 for i in 0..size {
368 let control_val = (i & control_bit) >> control.0;
369 let target_val = (i & target_bit) >> target.0;
370 let basis_idx = control_val * 2 + target_val;
371
372 if basis_idx < 4 {
373 let j = i ^ target_bit;
375 let k = i ^ control_bit;
376 let l = i ^ control_bit ^ target_bit;
377
378 if i <= j && i <= k && i <= l {
379 let amps = [
381 buffer.data[i],
382 buffer.data[j],
383 buffer.data[k],
384 buffer.data[l],
385 ];
386
387 for (idx, &state_idx) in [i, j, k, l].iter().enumerate() {
388 let mut new_amp = Complex64::new(0.0, 0.0);
389 for j in 0..4 {
390 new_amp += gate_matrix[idx * 4 + j] * amps[j];
391 }
392 buffer.data[state_idx] = new_amp;
393 }
394 }
395 }
396 }
397
398 if let Ok(mut metrics) = self.metrics.lock() {
400 metrics.kernel_executions += 1;
401 let duration = start.elapsed();
402 let duration_us = duration.as_nanos() as f64 / 1000.0;
403
404 let alpha = 0.1;
405 metrics.avg_kernel_time_us =
406 alpha * duration_us + (1.0 - alpha) * metrics.avg_kernel_time_us;
407 }
408
409 Ok(())
410 }
411}
412
413impl GpuKernel for SciRS2KernelAdapter {
414 fn apply_single_qubit_gate(
415 &self,
416 state: &mut dyn GpuBuffer,
417 gate_matrix: &[Complex64; 4],
418 qubit: crate::qubit::QubitId,
419 n_qubits: usize,
420 ) -> QuantRS2Result<()> {
421 self.execute_single_qubit_kernel(state, gate_matrix, qubit, n_qubits)
422 }
423
424 fn apply_two_qubit_gate(
425 &self,
426 state: &mut dyn GpuBuffer,
427 gate_matrix: &[Complex64; 16],
428 control: crate::qubit::QubitId,
429 target: crate::qubit::QubitId,
430 n_qubits: usize,
431 ) -> QuantRS2Result<()> {
432 self.execute_two_qubit_kernel(state, gate_matrix, control, target, n_qubits)
433 }
434
435 fn apply_multi_qubit_gate(
436 &self,
437 state: &mut dyn GpuBuffer,
438 gate_matrix: &scirs2_core::ndarray::Array2<Complex64>,
439 qubits: &[crate::qubit::QubitId],
440 n_qubits: usize,
441 ) -> QuantRS2Result<()> {
442 use std::time::Instant;
443 let start = Instant::now();
444
445 let buffer = state
446 .as_any_mut()
447 .downcast_mut::<SciRS2BufferAdapter>()
448 .ok_or_else(|| QuantRS2Error::InvalidInput("Invalid buffer type".to_string()))?;
449
450 let num_target_qubits = qubits.len();
451 let gate_size = 1 << num_target_qubits;
452
453 if gate_matrix.nrows() != gate_size || gate_matrix.ncols() != gate_size {
454 return Err(QuantRS2Error::InvalidInput(
455 "Gate matrix size doesn't match number of qubits".to_string(),
456 ));
457 }
458
459 let state_size = 1 << n_qubits;
460
461 for i in 0..state_size {
463 let mut source_idx = 0;
465 for (bit_pos, &qubit) in qubits.iter().enumerate() {
466 if (i >> qubit.0) & 1 == 1 {
467 source_idx |= 1 << bit_pos;
468 }
469 }
470
471 let mut new_amplitude = Complex64::new(0.0, 0.0);
473 for j in 0..gate_size {
474 let mut target_state = i;
476 for (bit_pos, &qubit) in qubits.iter().enumerate() {
477 let target_bit = (j >> bit_pos) & 1;
478 if target_bit == 1 {
479 target_state |= 1 << qubit.0;
480 } else {
481 target_state &= !(1 << qubit.0);
482 }
483 }
484
485 new_amplitude += gate_matrix[[source_idx, j]] * buffer.data[target_state];
486 }
487
488 buffer.data[i] = new_amplitude;
489 }
490
491 if let Ok(mut metrics) = self.metrics.lock() {
493 metrics.kernel_executions += 1;
494 let duration = start.elapsed();
495 let duration_us = duration.as_nanos() as f64 / 1000.0;
496
497 let alpha = 0.1;
498 metrics.avg_kernel_time_us =
499 alpha * duration_us + (1.0 - alpha) * metrics.avg_kernel_time_us;
500 }
501
502 Ok(())
503 }
504
505 fn measure_qubit(
506 &self,
507 state: &dyn GpuBuffer,
508 qubit: crate::qubit::QubitId,
509 _n_qubits: usize,
510 ) -> QuantRS2Result<(bool, f64)> {
511 let buffer = state
512 .as_any()
513 .downcast_ref::<SciRS2BufferAdapter>()
514 .ok_or_else(|| QuantRS2Error::InvalidInput("Invalid buffer type".to_string()))?;
515
516 let qubit_bit = 1 << qubit.0;
517 let mut prob_one = 0.0;
518
519 for (i, &litude) in buffer.data.iter().enumerate() {
521 if i & qubit_bit != 0 {
522 prob_one += amplitude.norm_sqr();
523 }
524 }
525
526 use scirs2_core::random::prelude::*;
528 let outcome = thread_rng().gen::<f64>() < prob_one;
529
530 Ok((outcome, if outcome { prob_one } else { 1.0 - prob_one }))
531 }
532
533 fn expectation_value(
534 &self,
535 state: &dyn GpuBuffer,
536 observable: &scirs2_core::ndarray::Array2<Complex64>,
537 qubits: &[crate::qubit::QubitId],
538 n_qubits: usize,
539 ) -> QuantRS2Result<f64> {
540 let buffer = state
541 .as_any()
542 .downcast_ref::<SciRS2BufferAdapter>()
543 .ok_or_else(|| QuantRS2Error::InvalidInput("Invalid buffer type".to_string()))?;
544
545 let num_obs_qubits = qubits.len();
546 let obs_size = 1 << num_obs_qubits;
547
548 if observable.nrows() != obs_size || observable.ncols() != obs_size {
549 return Err(QuantRS2Error::InvalidInput(
550 "Observable matrix size doesn't match number of qubits".to_string(),
551 ));
552 }
553
554 let mut expectation = 0.0;
555 let state_size = 1 << n_qubits;
556
557 for i in 0..state_size {
558 for j in 0..state_size {
559 let mut obs_i = 0;
561 let mut obs_j = 0;
562 let mut matches = true;
563
564 for (bit_pos, &qubit) in qubits.iter().enumerate() {
565 let bit_i = (i >> qubit.0) & 1;
566 let bit_j = (j >> qubit.0) & 1;
567 obs_i |= bit_i << bit_pos;
568 obs_j |= bit_j << bit_pos;
569
570 if qubits.iter().all(|&q| q.0 != qubit.0) && bit_i != bit_j {
572 matches = false;
573 break;
574 }
575 }
576
577 if matches {
578 let matrix_element = observable[[obs_i, obs_j]];
579 expectation += (buffer.data[i].conj() * matrix_element * buffer.data[j]).re;
580 }
581 }
582 }
583
584 Ok(expectation)
585 }
586}
587
588pub struct SciRS2GpuBackend {
590 kernel: SciRS2KernelAdapter,
591 config: SciRS2GpuConfig,
592 device_info: String,
593}
594
595impl SciRS2GpuBackend {
596 pub fn new() -> QuantRS2Result<Self> {
598 Self::with_config(SciRS2GpuConfig::default())
599 }
600
601 pub fn with_config(config: SciRS2GpuConfig) -> QuantRS2Result<Self> {
603 let mut kernel = SciRS2KernelAdapter::with_config(config.clone());
604
605 #[cfg(feature = "gpu")]
607 let _ = kernel.initialize_gpu();
608
609 let device_info = format!(
610 "SciRS2 GPU Backend - Memory: {}MB, SIMD Level: {}, Cache: {}",
611 config.max_memory_mb, config.simd_level, config.enable_kernel_cache
612 );
613
614 Ok(Self {
615 kernel,
616 config,
617 device_info,
618 })
619 }
620
621 pub fn get_performance_metrics(&self) -> SciRS2GpuMetrics {
623 if let Ok(metrics) = self.kernel.metrics.lock() {
624 metrics.clone()
625 } else {
626 SciRS2GpuMetrics {
627 kernel_executions: 0,
628 avg_kernel_time_us: 0.0,
629 memory_bandwidth_utilization: 0.0,
630 compute_utilization: 0.0,
631 cache_hit_rate: 0.0,
632 memory_usage_bytes: 0,
633 }
634 }
635 }
636
637 pub fn optimization_report(&self) -> String {
639 let metrics = self.get_performance_metrics();
640 format!(
641 "SciRS2 GPU Optimization Report:\n\
642 - Kernel Executions: {}\n\
643 - Average Kernel Time: {:.2} μs\n\
644 - Memory Bandwidth: {:.1}%\n\
645 - Compute Utilization: {:.1}%\n\
646 - Cache Hit Rate: {:.1}%\n\
647 - Memory Usage: {:.2} MB",
648 metrics.kernel_executions,
649 metrics.avg_kernel_time_us,
650 metrics.memory_bandwidth_utilization * 100.0,
651 metrics.compute_utilization * 100.0,
652 metrics.cache_hit_rate * 100.0,
653 metrics.memory_usage_bytes as f64 / (1024.0 * 1024.0)
654 )
655 }
656}
657
658impl QuantumGpuBackend for SciRS2GpuBackend {
659 fn is_available() -> bool
660 where
661 Self: Sized,
662 {
663 is_gpu_available()
664 }
665
666 fn name(&self) -> &str {
667 "SciRS2_GPU"
668 }
669
670 fn device_info(&self) -> String {
671 self.device_info.clone()
672 }
673
674 fn allocate_state_vector(&self, n_qubits: usize) -> QuantRS2Result<Box<dyn GpuBuffer>> {
675 let size = 1 << n_qubits;
676 let mut buffer = SciRS2BufferAdapter::with_config(size, self.config.clone());
677
678 #[cfg(feature = "gpu")]
680 let _ = buffer.initialize_gpu();
681
682 Ok(Box::new(buffer))
683 }
684
685 fn allocate_density_matrix(&self, n_qubits: usize) -> QuantRS2Result<Box<dyn GpuBuffer>> {
686 let size = 1 << (2 * n_qubits); let mut buffer = SciRS2BufferAdapter::with_config(size, self.config.clone());
688
689 #[cfg(feature = "gpu")]
690 let _ = buffer.initialize_gpu();
691
692 Ok(Box::new(buffer))
693 }
694
695 fn kernel(&self) -> &dyn GpuKernel {
696 &self.kernel
697 }
698}
699
700#[cfg(feature = "gpu")]
702pub fn get_scirs2_gpu_device() -> QuantRS2Result<GpuDevice> {
703 let _backends = vec![
706 GpuBackend::CUDA,
707 #[cfg(target_os = "macos")]
708 GpuBackend::Metal,
709 GpuBackend::OpenCL,
710 ];
711
712 use crate::gpu::large_scale_simulation::GpuDevice as LargeScaleGpuDevice;
714
715 let _device = LargeScaleGpuDevice {
716 id: 0,
717 name: "SciRS2 GPU Device".to_string(),
718 backend: GpuBackend::CUDA, memory_size: 8 * 1024 * 1024 * 1024, compute_units: 80,
721 max_work_group_size: 1024,
722 supports_double_precision: true,
723 is_available: true,
724 };
725
726 Err(QuantRS2Error::BackendExecutionFailed(
729 "SciRS2 GPU API not yet integrated".to_string(),
730 ))
731}
732
733#[cfg(feature = "gpu")]
735pub fn register_quantum_kernel(name: &str, kernel_source: &str) -> QuantRS2Result<()> {
736 use std::sync::OnceLock;
739 static KERNEL_REGISTRY: OnceLock<std::sync::Mutex<HashMap<String, String>>> = OnceLock::new();
740
741 let registry = KERNEL_REGISTRY.get_or_init(|| std::sync::Mutex::new(HashMap::new()));
742 if let Ok(mut registry_lock) = registry.lock() {
743 registry_lock.insert(name.to_string(), kernel_source.to_string());
744 }
745
746 Ok(())
747}
748
749pub fn register_compiled_kernel(name: &str, kernel_binary: &[u8]) -> QuantRS2Result<()> {
751 let _ = (name, kernel_binary);
753 Ok(())
754}
755
756pub fn is_gpu_available() -> bool {
758 #[cfg(feature = "gpu")]
759 {
760 true
763 }
764 #[cfg(not(feature = "gpu"))]
765 {
766 false
767 }
768}
769
770pub struct SciRS2GpuFactory;
772
773impl SciRS2GpuFactory {
774 pub fn create_best() -> QuantRS2Result<SciRS2GpuBackend> {
776 SciRS2GpuBackend::new()
777 }
778
779 pub fn create_with_config(config: SciRS2GpuConfig) -> QuantRS2Result<SciRS2GpuBackend> {
781 SciRS2GpuBackend::with_config(config)
782 }
783
784 pub fn create_qml_optimized() -> QuantRS2Result<SciRS2GpuBackend> {
786 let mut config = SciRS2GpuConfig::default();
787 config.simd_level = 3; config.max_memory_mb = 4096; config.compilation_flags.push("-DQML_OPTIMIZE".to_string());
790 SciRS2GpuBackend::with_config(config)
791 }
792
793 pub fn create_algorithm_optimized() -> QuantRS2Result<SciRS2GpuBackend> {
795 let mut config = SciRS2GpuConfig::default();
796 config.simd_level = 2; config.enable_load_balancing = true;
798 config
799 .compilation_flags
800 .push("-DALGORITHM_OPTIMIZE".to_string());
801 SciRS2GpuBackend::with_config(config)
802 }
803
804 pub fn available_backends() -> Vec<String> {
806 let mut backends = Vec::new();
807
808 #[cfg(feature = "gpu")]
809 {
810 backends.push("CUDA".to_string());
812
813 #[cfg(target_os = "macos")]
814 backends.push("Metal".to_string());
815
816 backends.push("OpenCL".to_string());
817 }
818
819 if backends.is_empty() {
820 backends.push("CPU_Fallback".to_string());
821 }
822
823 backends
824 }
825}
826
827pub fn get_gpu_system_info() -> HashMap<String, String> {
829 let mut info = HashMap::new();
830
831 info.insert(
833 "available_backends".to_string(),
834 SciRS2GpuFactory::available_backends().join(", "),
835 );
836
837 #[cfg(feature = "gpu")]
838 {
839 if let Ok(_device) = get_scirs2_gpu_device() {
840 info.insert("primary_device".to_string(), "GPU".to_string());
841 } else {
843 info.insert("primary_device".to_string(), "CPU".to_string());
844 }
845 }
846
847 #[cfg(not(feature = "gpu"))]
848 {
849 info.insert("primary_device".to_string(), "CPU".to_string());
850 info.insert("gpu_support".to_string(), "Disabled".to_string());
851 }
852
853 info
854}
855
856#[cfg(test)]
857mod tests {
858 use super::*;
859
860 #[test]
861 fn test_gpu_availability_check() {
862 let _available = is_gpu_available();
864 }
865
866 #[test]
867 fn test_buffer_adapter_creation() {
868 let adapter = SciRS2BufferAdapter::new(1024);
869 assert_eq!(adapter.size, 1024);
870 }
871
872 #[test]
873 fn test_buffer_adapter_with_config() {
874 let config = SciRS2GpuConfig {
875 max_memory_mb: 512,
876 simd_level: 1,
877 ..Default::default()
878 };
879 let adapter = SciRS2BufferAdapter::with_config(256, config.clone());
880 assert_eq!(adapter.size, 256);
881 assert_eq!(adapter.config.max_memory_mb, 512);
882 assert_eq!(adapter.config.simd_level, 1);
883 }
884
885 #[test]
886 fn test_kernel_adapter_creation() {
887 let adapter = SciRS2KernelAdapter::new();
888 assert!(adapter.kernel_cache.is_empty());
889 }
890
891 #[test]
892 fn test_scirs2_gpu_backend_creation() {
893 let backend = SciRS2GpuBackend::new()
894 .expect("Failed to create SciRS2 GPU backend in test_scirs2_gpu_backend_creation");
895 assert_eq!(backend.name(), "SciRS2_GPU");
896 assert!(!backend.device_info().is_empty());
897 }
898
899 #[test]
900 fn test_buffer_upload_download() {
901 let mut buffer = SciRS2BufferAdapter::new(4);
902 let data = vec![
903 Complex64::new(1.0, 0.0),
904 Complex64::new(0.0, 1.0),
905 Complex64::new(-1.0, 0.0),
906 Complex64::new(0.0, -1.0),
907 ];
908
909 buffer
910 .upload(&data)
911 .expect("Failed to upload data in test_buffer_upload_download");
912
913 let mut downloaded = vec![Complex64::new(0.0, 0.0); 4];
914 buffer
915 .download(&mut downloaded)
916 .expect("Failed to download data in test_buffer_upload_download");
917
918 for (original, downloaded) in data.iter().zip(downloaded.iter()) {
919 assert!((original - downloaded).norm() < 1e-10);
920 }
921 }
922
923 #[test]
924 fn test_kernel_execution() {
925 let kernel = SciRS2KernelAdapter::new();
926 let mut buffer = SciRS2BufferAdapter::new(4); let initial_state = vec![
930 Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), Complex64::new(0.0, 0.0), ];
935 buffer
936 .upload(&initial_state)
937 .expect("Failed to upload initial state in test_kernel_execution");
938
939 let x_gate = [
941 Complex64::new(0.0, 0.0),
942 Complex64::new(1.0, 0.0),
943 Complex64::new(1.0, 0.0),
944 Complex64::new(0.0, 0.0),
945 ];
946
947 kernel
948 .apply_single_qubit_gate(
949 &mut buffer as &mut dyn GpuBuffer,
950 &x_gate,
951 crate::qubit::QubitId(0),
952 2,
953 )
954 .expect("Failed to apply single qubit gate in test_kernel_execution");
955
956 let mut result = vec![Complex64::new(0.0, 0.0); 4];
958 buffer
959 .download(&mut result)
960 .expect("Failed to download result in test_kernel_execution");
961
962 assert!((result[0] - Complex64::new(0.0, 0.0)).norm() < 1e-10); assert!((result[1] - Complex64::new(1.0, 0.0)).norm() < 1e-10); assert!((result[2] - Complex64::new(0.0, 0.0)).norm() < 1e-10); assert!((result[3] - Complex64::new(0.0, 0.0)).norm() < 1e-10); }
967
968 #[test]
969 fn test_gpu_factory() {
970 let backend = SciRS2GpuFactory::create_best()
971 .expect("Failed to create best GPU backend in test_gpu_factory");
972 assert_eq!(backend.name(), "SciRS2_GPU");
973
974 let backends = SciRS2GpuFactory::available_backends();
975 assert!(!backends.is_empty());
976 }
977
978 #[test]
979 fn test_qml_optimized_backend() {
980 let backend = SciRS2GpuFactory::create_qml_optimized()
981 .expect("Failed to create QML-optimized backend in test_qml_optimized_backend");
982 assert_eq!(backend.config.simd_level, 3);
983 assert_eq!(backend.config.max_memory_mb, 4096);
984 assert!(backend
985 .config
986 .compilation_flags
987 .contains(&"-DQML_OPTIMIZE".to_string()));
988 }
989
990 #[test]
991 fn test_system_info() {
992 let info = get_gpu_system_info();
993 assert!(info.contains_key("available_backends"));
994 assert!(info.contains_key("primary_device"));
995 }
996
997 #[test]
998 fn test_performance_metrics() {
999 let backend =
1000 SciRS2GpuBackend::new().expect("Failed to create backend in test_performance_metrics");
1001 let metrics = backend.get_performance_metrics();
1002
1003 assert_eq!(metrics.kernel_executions, 0);
1005
1006 let report = backend.optimization_report();
1007 assert!(report.contains("SciRS2 GPU Optimization Report"));
1008 }
1009
1010 #[test]
1011 fn test_config_validation() {
1012 let config = SciRS2GpuConfig {
1013 device_id: 0,
1014 memory_pool_size: 1024 * 1024 * 1024,
1015 enable_profiling: false,
1016 enable_async: true,
1017 enable_kernel_cache: true,
1018 max_memory_mb: 1024,
1019 simd_level: 2,
1020 enable_load_balancing: true,
1021 compilation_flags: vec!["-O3".to_string()],
1022 };
1023
1024 let backend = SciRS2GpuBackend::with_config(config.clone())
1025 .expect("Failed to create backend with config in test_config_validation");
1026 assert_eq!(backend.config.max_memory_mb, 1024);
1027 assert_eq!(backend.config.simd_level, 2);
1028 assert!(backend.config.enable_kernel_cache);
1029 }
1030}