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