1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
//! Enhanced GPU kernel optimization for specialized quantum gates
//!
//! This module provides high-performance GPU kernels optimized for specialized quantum gates
//! including holonomic gates, post-quantum cryptography gates, and quantum ML gates.
//! It leverages tensor cores, optimized memory access patterns, and gate fusion for maximum performance.
use crate::{
error::{QuantRS2Error, QuantRS2Result},
gate::GateOp,
qubit::QubitId,
};
use scirs2_core::Complex64;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
/// Map an OxiCUDA driver error into a `QuantRS2Error` without losing detail.
#[cfg(feature = "gpu")]
fn map_cuda_err(err: oxicuda::CudaError) -> QuantRS2Error {
QuantRS2Error::BackendExecutionFailed(format!("OxiCUDA driver error: {err:?}"))
}
/// Honest error for a specialized CUDA kernel whose device source is not yet authored.
fn uncompiled_kernel_err(name: &str) -> QuantRS2Error {
QuantRS2Error::UnsupportedOperation(format!(
"specialized CUDA kernel `{name}` is not available: real PTX device code has not been \
authored yet (no fabricated kernel is returned)"
))
}
/// Honest error for a specialized WebGPU shader whose WGSL source is not yet authored.
fn uncompiled_shader_err(name: &str) -> QuantRS2Error {
QuantRS2Error::UnsupportedOperation(format!(
"specialized WebGPU shader `{name}` is not available: real WGSL device code has not been \
authored yet (no fabricated shader is returned)"
))
}
/// Query real WebGPU adapter limits via wgpu.
///
/// Requests the first available adapter (any backend) and reports its genuine
/// `max_compute_workgroup_size_x`. Returns an honest error when no adapter is
/// present — never a hardcoded limit.
#[cfg(feature = "gpu")]
fn query_webgpu_limits() -> QuantRS2Result<WebGpuLimits> {
// wgpu 29: `InstanceDescriptor` has no `Default`; use the explicit ctor.
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: None,
// wgpu 30: `apply_limit_buckets` is a new anti-fingerprinting knob (relevant to
// untrusted/browser contexts); native driver-limits queries want the real limits,
// so leave it at its `Default` (`false`). `..Default::default()` also keeps this
// call forward-compatible with any future fields wgpu adds to this struct.
..Default::default()
}))
.map_err(|e| {
QuantRS2Error::BackendExecutionFailed(format!("no WebGPU adapter available: {e}"))
})?;
let limits = adapter.limits();
Ok(WebGpuLimits {
max_compute_workgroup_size: limits.max_compute_workgroup_size_x,
})
}
/// Apply a dense `d x d` unitary (`d = 2^k`, row-major) to the `k` targeted
/// qubits of a state vector, in place, on the CPU.
///
/// This is a genuine matrix-vector application over each targeted-qubit
/// subspace (LSB qubit ordering, matching the rest of the crate): for every
/// fixed configuration of the untargeted qubits, the `d` amplitudes selected by
/// the targeted qubits are gathered and updated as `out[i] = Σ_j M[i*d+j]·in[j]`.
///
/// Returns an error on dimension mismatch or out-of-range qubit — it never
/// silently skips work.
fn apply_dense_gate_cpu(
state: &mut [Complex64],
matrix: &[Complex64],
target_qubits: &[QubitId],
) -> QuantRS2Result<()> {
let state_len = state.len();
if state_len == 0 || !state_len.is_power_of_two() {
return Err(QuantRS2Error::InvalidInput(format!(
"state vector length must be a non-zero power of two, got {state_len}"
)));
}
let n_qubits = state_len.trailing_zeros() as usize;
let gate_qubits = target_qubits.len();
if gate_qubits == 0 {
return Err(QuantRS2Error::InvalidInput(
"holonomic/dense gate requires at least one target qubit".to_string(),
));
}
if gate_qubits > n_qubits {
return Err(QuantRS2Error::InvalidInput(format!(
"gate acts on {gate_qubits} qubits but the state only has {n_qubits}"
)));
}
let gate_dim = 1usize << gate_qubits;
if matrix.len() != gate_dim * gate_dim {
return Err(QuantRS2Error::InvalidInput(format!(
"gate matrix has {} entries but a {gate_dim}x{gate_dim} ({}) matrix was expected",
matrix.len(),
gate_dim * gate_dim
)));
}
// Sorted, de-duplicated, in-range target bit positions (LSB ordering).
let mut qubit_indices: Vec<usize> = target_qubits.iter().map(|q| q.0 as usize).collect();
qubit_indices.sort_unstable();
for &idx in &qubit_indices {
if idx >= n_qubits {
return Err(QuantRS2Error::InvalidInput(format!(
"target qubit {idx} out of range for a {n_qubits}-qubit state"
)));
}
}
qubit_indices.dedup();
if qubit_indices.len() != gate_qubits {
return Err(QuantRS2Error::InvalidInput(
"duplicate target qubits supplied to dense gate".to_string(),
));
}
let unaffected_qubits = n_qubits - gate_qubits;
let iterations = 1usize << unaffected_qubits;
let mut indices = vec![0usize; gate_dim];
let mut temp = vec![Complex64::new(0.0, 0.0); gate_dim];
for i in 0..iterations {
// Scatter the `unaffected_qubits` index bits of `i` into the positions
// NOT occupied by target qubits to form the base index.
let mut base = 0usize;
let mut remaining = i;
let mut qubit_pos = 0usize;
for bit in 0..n_qubits {
if qubit_pos < gate_qubits && bit == qubit_indices[qubit_pos] {
qubit_pos += 1;
} else {
if remaining & 1 == 1 {
base |= 1 << bit;
}
remaining >>= 1;
}
}
// Enumerate the `gate_dim` amplitudes of this subspace.
for (j, slot) in indices.iter_mut().enumerate() {
let mut idx = base;
for (k, &qubit_idx) in qubit_indices.iter().enumerate() {
if (j >> k) & 1 == 1 {
idx |= 1 << qubit_idx;
}
}
*slot = idx;
}
// Gather, multiply by the dense matrix, scatter back.
for (t, &idx) in indices.iter().enumerate() {
temp[t] = state[idx];
}
for (row, &idx) in indices.iter().enumerate() {
let mut sum = Complex64::new(0.0, 0.0);
let row_off = row * gate_dim;
for (col, &) in temp.iter().enumerate() {
sum += matrix[row_off + col] * amp;
}
state[idx] = sum;
}
}
Ok(())
}
/// Enhanced GPU kernel manager for specialized gates
pub struct SpecializedGpuKernels {
/// CUDA context for kernel execution
cuda_context: Option<CudaSpecializedContext>,
/// WebGPU context for cross-platform support
webgpu_context: Option<WebGpuSpecializedContext>,
/// Kernel cache for compiled kernels
kernel_cache: Arc<Mutex<KernelCache>>,
/// Performance statistics
performance_stats: Arc<Mutex<PerformanceStats>>,
/// Optimization configuration
config: OptimizationConfig,
}
/// CUDA context specialized for quantum gates
pub struct CudaSpecializedContext {
/// Device compute capability
#[allow(dead_code)]
compute_capability: (i32, i32),
/// Tensor core availability
has_tensor_cores: bool,
/// Maximum shared memory per block
#[allow(dead_code)]
max_shared_memory: usize,
/// Warp size
#[allow(dead_code)]
warp_size: usize,
/// Compiled kernels
kernels: HashMap<String, CompiledKernel>,
}
/// WebGPU context for cross-platform support
pub struct WebGpuSpecializedContext {
/// Device limits
#[allow(dead_code)]
device_limits: WebGpuLimits,
/// Compiled shaders
#[allow(dead_code)]
shaders: HashMap<String, CompiledShader>,
/// Buffer pools for efficient memory management
#[allow(dead_code)]
buffer_pools: HashMap<String, BufferPool>,
}
/// Kernel cache for compiled GPU kernels
pub struct KernelCache {
/// Cached CUDA kernels
#[allow(dead_code)]
cuda_kernels: HashMap<String, CachedCudaKernel>,
/// Cached WebGPU shaders
#[allow(dead_code)]
webgpu_shaders: HashMap<String, CachedWebGpuShader>,
/// Cache hit statistics
cache_stats: CacheStatistics,
}
/// Performance statistics for optimization analysis
pub struct PerformanceStats {
/// Kernel execution times
kernel_times: HashMap<String, Vec<f64>>,
/// Memory bandwidth utilization
memory_bandwidth: HashMap<String, f64>,
/// Tensor core utilization
tensor_core_utilization: f64,
/// Cache hit rates
#[allow(dead_code)]
cache_hit_rates: HashMap<String, f64>,
}
/// GPU optimization configuration
#[derive(Debug, Clone)]
pub struct OptimizationConfig {
/// Enable tensor core optimization
pub use_tensor_cores: bool,
/// Enable memory access optimization
pub optimize_memory_access: bool,
/// Enable gate fusion
pub enable_gate_fusion: bool,
/// Maximum fusion chain length
pub max_fusion_length: usize,
/// Memory coalescing threshold
pub coalescing_threshold: usize,
/// Use mixed precision
pub use_mixed_precision: bool,
}
impl Default for OptimizationConfig {
fn default() -> Self {
Self {
use_tensor_cores: true,
optimize_memory_access: true,
enable_gate_fusion: true,
max_fusion_length: 8,
coalescing_threshold: 32,
use_mixed_precision: true,
}
}
}
impl SpecializedGpuKernels {
/// Create a new specialized GPU kernel manager
pub fn new(config: OptimizationConfig) -> QuantRS2Result<Self> {
let cuda_context = Self::initialize_cuda_context(&config)?;
let webgpu_context = Self::initialize_webgpu_context(&config)?;
Ok(Self {
cuda_context,
webgpu_context,
kernel_cache: Arc::new(Mutex::new(KernelCache::new())),
performance_stats: Arc::new(Mutex::new(PerformanceStats::new())),
config,
})
}
/// Initialize a CUDA context for specialized kernels.
///
/// Returns `Ok(None)` when no CUDA device is present (the honest result on a
/// GPU-less host) *or* when the specialized-gate device kernels are not yet
/// authored. A `CudaSpecializedContext` is only constructed when a real
/// device is queried successfully AND every required kernel compiles; since
/// the PTX gate kernels are still DEFERRED, this currently yields `None`
/// even on a CUDA host rather than fabricating compiled kernels.
fn initialize_cuda_context(
config: &OptimizationConfig,
) -> QuantRS2Result<Option<CudaSpecializedContext>> {
// Real availability probe.
if !Self::is_cuda_available() {
return Ok(None);
}
// Real device queries — genuine values from the driver.
let compute_capability = Self::get_compute_capability()?;
let has_tensor_cores = compute_capability.0 >= 7; // Volta and later
let device_props = Self::get_device_properties()?;
// Attempt to compile the specialized gate kernels. These currently
// return an honest error (no PTX source yet); we therefore treat a
// compilation failure as "specialized CUDA path unavailable" and return
// None instead of fabricating a usable context.
let kernel_specs: [(
&str,
fn(&OptimizationConfig) -> QuantRS2Result<CompiledKernel>,
); 5] = [
("holonomic_gate", Self::compile_holonomic_kernel),
("post_quantum_hash", Self::compile_post_quantum_kernel),
("quantum_ml_attention", Self::compile_qml_attention_kernel),
(
"fused_rotation_sequence",
Self::compile_fused_rotation_kernel,
),
("tensor_core_matmul", Self::compile_tensor_core_kernel),
];
let mut kernels = HashMap::with_capacity(kernel_specs.len());
for (name, compile) in kernel_specs {
match compile(config) {
Ok(kernel) => {
kernels.insert(name.to_string(), kernel);
}
// Specialized kernels not yet authored — honest "unavailable".
Err(_) => return Ok(None),
}
}
Ok(Some(CudaSpecializedContext {
compute_capability,
has_tensor_cores,
max_shared_memory: device_props.max_shared_memory,
warp_size: device_props.warp_size,
kernels,
}))
}
/// Initialize a WebGPU context for specialized shaders.
///
/// Returns `Ok(None)` when no WebGPU adapter is present or when the
/// specialized-gate WGSL shaders are not yet authored. A context is only
/// built when a real adapter is queried AND every shader compiles; since the
/// WGSL gate shaders are still DEFERRED, this currently yields `None` rather
/// than fabricating compiled shaders.
fn initialize_webgpu_context(
config: &OptimizationConfig,
) -> QuantRS2Result<Option<WebGpuSpecializedContext>> {
// Real adapter limits; absence of an adapter is an honest "unavailable".
let device_limits = match Self::get_webgpu_limits() {
Ok(limits) => limits,
Err(_) => return Ok(None),
};
let shader_specs: [(
&str,
fn(&OptimizationConfig) -> QuantRS2Result<CompiledShader>,
); 3] = [
("holonomic_gate", Self::compile_holonomic_shader),
("post_quantum_hash", Self::compile_post_quantum_shader),
("quantum_ml_attention", Self::compile_qml_attention_shader),
];
let mut shaders = HashMap::with_capacity(shader_specs.len());
for (name, compile) in shader_specs {
match compile(config) {
Ok(shader) => {
shaders.insert(name.to_string(), shader);
}
// Specialized shaders not yet authored — honest "unavailable".
Err(_) => return Ok(None),
}
}
let mut buffer_pools = HashMap::new();
buffer_pools.insert("state_vectors".to_string(), BufferPool::new(1024 * 1024)); // 1MB initial
buffer_pools.insert("gate_matrices".to_string(), BufferPool::new(512 * 1024)); // 512KB initial
buffer_pools.insert("temporary_buffers".to_string(), BufferPool::new(256 * 1024)); // 256KB initial
Ok(Some(WebGpuSpecializedContext {
device_limits,
shaders,
buffer_pools,
}))
}
/// Apply a holonomic (unitary) gate to the targeted qubits.
///
/// Dispatches to a GPU kernel when a specialized GPU context is available;
/// otherwise computes the result on the CPU. The CPU path is a *real*
/// matrix-vector application over the targeted-qubit subspace (it is not a
/// no-op). Because the specialized GPU gate kernels are still DEFERRED, the
/// GPU contexts are currently `None`, so this resolves to the CPU path —
/// which performs the genuine computation.
pub fn apply_holonomic_gate(
&self,
state: &mut [Complex64],
holonomy_matrix: &[Complex64],
target_qubits: &[QubitId],
) -> QuantRS2Result<()> {
let state_size = state.len();
// Choose execution path based on size and available hardware contexts.
if state_size > 1024 && self.cuda_context.is_some() {
self.apply_holonomic_gate_cuda(state, holonomy_matrix, target_qubits)
} else if self.webgpu_context.is_some() {
self.apply_holonomic_gate_webgpu(state, holonomy_matrix, target_qubits)
} else {
// CPU fallback — real computation, honestly labeled.
apply_dense_gate_cpu(state, holonomy_matrix, target_qubits)
}
}
/// Apply a holonomic gate using a CUDA kernel.
///
/// This path is only taken when a real CUDA specialized context exists. The
/// PTX device kernel for holonomic gates is DEFERRED, so this returns an
/// honest error rather than pretending a kernel ran. (In practice the
/// dispatcher never reaches here because `cuda_context` is `None`.)
fn apply_holonomic_gate_cuda(
&self,
_state: &mut [Complex64],
_holonomy_matrix: &[Complex64],
_target_qubits: &[QubitId],
) -> QuantRS2Result<()> {
Err(uncompiled_kernel_err("holonomic_gate"))
}
/// Apply a post-quantum cryptographic hash gate.
///
/// These compression schemes (quantum sponge / Merkle tree / Grover) are
/// implemented as GPU device kernels that are not yet authored, and they
/// have no defined CPU reference here. Rather than silently returning
/// success without touching `state` (the previous fabricated behavior), this
/// returns an honest error. DEFERRED until the real kernels exist.
pub fn apply_post_quantum_hash_gate(
&self,
_state: &mut [Complex64],
_hash_circuit: &[Complex64],
compression_type: PostQuantumCompressionType,
) -> QuantRS2Result<()> {
let scheme = match compression_type {
PostQuantumCompressionType::QuantumSponge { .. } => "quantum_sponge",
PostQuantumCompressionType::QuantumMerkleTree { .. } => "quantum_merkle_tree",
PostQuantumCompressionType::QuantumGrover { .. } => "quantum_grover",
};
Err(QuantRS2Error::UnsupportedOperation(format!(
"post-quantum hash gate `{scheme}` is not implemented: the GPU kernel is DEFERRED and \
there is no CPU reference (refusing to fabricate a no-op success)"
)))
}
/// Apply a quantum ML attention mechanism.
///
/// The specialized attention kernels (CUDA/WebGPU) are not yet authored and
/// there is no defined CPU reference for the previously no-op fallback.
/// Returns an honest error rather than silently returning success without
/// transforming `state`. DEFERRED until the real kernels exist.
pub fn apply_quantum_ml_attention(
&self,
_state: &mut [Complex64],
_query_params: &[Complex64],
_key_params: &[Complex64],
_value_params: &[Complex64],
_num_heads: usize,
) -> QuantRS2Result<()> {
Err(QuantRS2Error::UnsupportedOperation(
"quantum ML attention is not implemented: the specialized GPU kernels are DEFERRED and \
there is no CPU reference (refusing to fabricate a no-op success)"
.to_string(),
))
}
/// Apply a sequence of gates to the state vector.
///
/// Each gate is applied with a *real* matrix-vector update on the CPU via
/// [`apply_single_gate_optimized`]. Gate *fusion* (merging adjacent gates
/// into a single combined matrix for fewer passes) is DEFERRED:
/// [`analyze_gate_fusion_opportunities`] currently finds no chains, so this
/// reduces to honest per-gate application. The result is numerically
/// correct; only the fused-pass optimization is missing.
pub fn apply_fused_gate_sequence(
&self,
state: &mut [Complex64],
gates: &[Box<dyn GateOp>],
) -> QuantRS2Result<()> {
// Try to discover fusion chains (currently always empty — DEFERRED).
let fusion_chains = if self.config.enable_gate_fusion && gates.len() >= 2 {
self.analyze_gate_fusion_opportunities(gates)?
} else {
Vec::new()
};
if fusion_chains.is_empty() {
// No fusion available: apply each gate individually (real compute).
for gate in gates {
self.apply_single_gate_optimized(state, gate.as_ref())?;
}
return Ok(());
}
// Fusion path is not yet implemented; the only honest action for a
// non-empty chain is per-gate application of its members.
for chain in fusion_chains {
for gate in &chain.gates {
self.apply_single_gate_optimized(state, gate.as_ref())?;
}
}
Ok(())
}
/// Record a real kernel execution time (milliseconds) for reporting.
///
/// Only invoked from paths that actually executed a kernel; it is never fed
/// a fabricated constant.
fn update_performance_stats(&self, kernel_name: &str, execution_time: f64) {
if let Ok(mut stats) = self.performance_stats.lock() {
stats
.kernel_times
.entry(kernel_name.to_string())
.or_default()
.push(execution_time);
}
// Silently ignore lock poisoning for performance stats update
}
/// Get performance report
pub fn get_performance_report(&self) -> PerformanceReport {
let stats = self
.performance_stats
.lock()
.unwrap_or_else(|e| e.into_inner());
let cache = self.kernel_cache.lock().unwrap_or_else(|e| e.into_inner());
PerformanceReport {
average_kernel_times: stats
.kernel_times
.iter()
.map(|(k, v)| (k.clone(), v.iter().sum::<f64>() / v.len() as f64))
.collect(),
cache_hit_rate: cache.cache_stats.overall_hit_rate(),
tensor_core_utilization: stats.tensor_core_utilization,
memory_bandwidth_utilization: stats.memory_bandwidth.values().sum::<f64>()
/ stats.memory_bandwidth.len() as f64,
}
}
/// Real CUDA availability probe via the OxiCUDA driver.
///
/// Loads `libcuda.so`/`nvcuda.dll` at runtime and counts devices. Returns
/// `true` only when the driver initializes AND at least one device exists.
/// Without the `gpu` feature, or with no device/driver, returns `false`
/// (the honest result).
fn is_cuda_available() -> bool {
crate::gpu::is_gpu_available()
}
/// Query the real compute capability of CUDA device 0.
///
/// Returns the genuine `(major, minor)` reported by the driver. Returns an
/// honest error when GPU support is not compiled in or no device exists —
/// it never fabricates a capability such as `(7, 5)`.
fn get_compute_capability() -> QuantRS2Result<(i32, i32)> {
#[cfg(feature = "gpu")]
{
oxicuda::init().map_err(map_cuda_err)?;
let device = oxicuda::Device::get(0).map_err(map_cuda_err)?;
device.compute_capability().map_err(map_cuda_err)
}
#[cfg(not(feature = "gpu"))]
{
Err(crate::error::QuantRS2Error::UnsupportedOperation(
"compute capability unavailable: GPU backend not linked (enable the `gpu` feature)"
.to_string(),
))
}
}
/// Query real device properties (warp size, shared memory) from device 0.
///
/// Returns genuine values from the OxiCUDA driver, or an honest error when
/// no GPU is available — never the previously hardcoded `49152`/`32`.
fn get_device_properties() -> QuantRS2Result<DeviceProperties> {
#[cfg(feature = "gpu")]
{
oxicuda::init().map_err(map_cuda_err)?;
let device = oxicuda::Device::get(0).map_err(map_cuda_err)?;
let warp_size = device.warp_size().map_err(map_cuda_err)? as usize;
let max_shared_memory =
device.max_shared_memory_per_block().map_err(map_cuda_err)? as usize;
Ok(DeviceProperties {
max_shared_memory,
warp_size,
})
}
#[cfg(not(feature = "gpu"))]
{
Err(crate::error::QuantRS2Error::UnsupportedOperation(
"device properties unavailable: GPU backend not linked (enable the `gpu` feature)"
.to_string(),
))
}
}
/// Query real WebGPU device limits via a wgpu adapter request.
///
/// Returns the genuine `max_compute_workgroup_size_x` from the first
/// available adapter, or an honest error when no WebGPU adapter is present —
/// never the previously hardcoded `256`.
fn get_webgpu_limits() -> QuantRS2Result<WebGpuLimits> {
#[cfg(feature = "gpu")]
{
query_webgpu_limits()
}
#[cfg(not(feature = "gpu"))]
{
Err(crate::error::QuantRS2Error::UnsupportedOperation(
"WebGPU limits unavailable: GPU backend not linked (enable the `gpu` feature)"
.to_string(),
))
}
}
// NOTE on kernel compilation: the specialized quantum-gate kernels
// (holonomic, post-quantum hash, QML attention, fused rotations,
// tensor-core matmul) require hand-authored PTX/WGSL device code that does
// NOT yet exist in this crate. Rather than fabricate a "compiled kernel"
// with a fake `last_execution_time`, these compile entry points return an
// honest error so a caller can never mistake an unbuilt kernel for a real
// one. See the module-level DEFERRED note. When real device source is added,
// wire `oxicuda::Module::from_ptx` / WGSL compilation here.
fn compile_holonomic_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
Err(uncompiled_kernel_err("holonomic_gate"))
}
fn compile_post_quantum_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
Err(uncompiled_kernel_err("post_quantum_hash"))
}
fn compile_qml_attention_kernel(
_config: &OptimizationConfig,
) -> QuantRS2Result<CompiledKernel> {
Err(uncompiled_kernel_err("quantum_ml_attention"))
}
fn compile_fused_rotation_kernel(
_config: &OptimizationConfig,
) -> QuantRS2Result<CompiledKernel> {
Err(uncompiled_kernel_err("fused_rotation_sequence"))
}
fn compile_tensor_core_kernel(_config: &OptimizationConfig) -> QuantRS2Result<CompiledKernel> {
Err(uncompiled_kernel_err("tensor_core_matmul"))
}
fn compile_holonomic_shader(_config: &OptimizationConfig) -> QuantRS2Result<CompiledShader> {
Err(uncompiled_shader_err("holonomic_gate"))
}
fn compile_post_quantum_shader(_config: &OptimizationConfig) -> QuantRS2Result<CompiledShader> {
Err(uncompiled_shader_err("post_quantum_hash"))
}
fn compile_qml_attention_shader(
_config: &OptimizationConfig,
) -> QuantRS2Result<CompiledShader> {
Err(uncompiled_shader_err("quantum_ml_attention"))
}
/// Apply a holonomic gate via a WebGPU compute shader.
///
/// The WGSL shader is DEFERRED, so this returns an honest error instead of
/// silently returning success. (Unreachable while `webgpu_context` is
/// `None`, but kept honest.)
fn apply_holonomic_gate_webgpu(
&self,
_state: &mut [Complex64],
_matrix: &[Complex64],
_qubits: &[QubitId],
) -> QuantRS2Result<()> {
Err(uncompiled_shader_err("holonomic_gate"))
}
/// Apply a single gate to the state vector on the CPU.
///
/// This is a *real* application: the gate's unitary matrix is fetched and
/// applied over the targeted-qubit subspace. It is the fallback used by
/// [`apply_fused_gate_sequence`] when no fusion is performed.
fn apply_single_gate_optimized(
&self,
state: &mut [Complex64],
gate: &dyn GateOp,
) -> QuantRS2Result<()> {
let matrix = gate.matrix()?;
let qubits = gate.qubits();
apply_dense_gate_cpu(state, &matrix, &qubits)
}
/// Analyze a gate list for fusion opportunities.
///
/// Gate fusion (merging adjacent rotations / Pauli strings / controlled
/// sequences into a single combined matrix) is not yet implemented. Rather
/// than fabricate fusion chains, this honestly reports *no* fusion
/// opportunities, so callers correctly fall back to applying each gate
/// individually via [`apply_single_gate_optimized`]. DEFERRED.
fn analyze_gate_fusion_opportunities(
&self,
_gates: &[Box<dyn GateOp>],
) -> QuantRS2Result<Vec<FusionChain>> {
Ok(Vec::new())
}
}
/// Supporting types and structures
#[derive(Debug, Clone)]
pub enum PostQuantumCompressionType {
QuantumSponge { rate: usize, capacity: usize },
QuantumMerkleTree { depth: usize, arity: usize },
QuantumGrover { iterations: usize },
}
#[derive(Debug, Clone)]
pub enum FusionType {
RotationSequence,
PauliString,
ControlledSequence,
None,
}
pub struct FusionChain {
pub gates: Vec<Box<dyn GateOp>>,
pub fusion_type: FusionType,
}
pub struct CompiledKernel {
pub name: String,
pub last_execution_time: f64,
}
pub struct CompiledShader {
pub name: String,
}
pub struct CachedCudaKernel {
pub kernel: CompiledKernel,
pub compilation_time: f64,
}
pub struct CachedWebGpuShader {
pub shader: CompiledShader,
pub compilation_time: f64,
}
pub struct CacheStatistics {
pub hits: usize,
pub misses: usize,
}
impl CacheStatistics {
pub fn overall_hit_rate(&self) -> f64 {
if self.hits + self.misses == 0 {
0.0
} else {
self.hits as f64 / (self.hits + self.misses) as f64
}
}
}
pub struct BufferPool {
pub initial_size: usize,
}
impl BufferPool {
pub const fn new(initial_size: usize) -> Self {
Self { initial_size }
}
}
pub struct DeviceProperties {
pub max_shared_memory: usize,
pub warp_size: usize,
}
pub struct WebGpuLimits {
pub max_compute_workgroup_size: u32,
}
pub struct PerformanceReport {
pub average_kernel_times: HashMap<String, f64>,
pub cache_hit_rate: f64,
pub tensor_core_utilization: f64,
pub memory_bandwidth_utilization: f64,
}
impl KernelCache {
pub fn new() -> Self {
Self {
cuda_kernels: HashMap::new(),
webgpu_shaders: HashMap::new(),
cache_stats: CacheStatistics { hits: 0, misses: 0 },
}
}
}
impl Default for KernelCache {
fn default() -> Self {
Self::new()
}
}
impl PerformanceStats {
pub fn new() -> Self {
Self {
kernel_times: HashMap::new(),
memory_bandwidth: HashMap::new(),
tensor_core_utilization: 0.0,
cache_hit_rates: HashMap::new(),
}
}
}
impl Default for PerformanceStats {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::f64::consts::FRAC_1_SQRT_2;
#[test]
fn test_specialized_gpu_kernels_creation() {
let config = OptimizationConfig::default();
let kernels = SpecializedGpuKernels::new(config);
assert!(kernels.is_ok());
}
#[test]
fn test_holonomic_identity_preserves_state() {
let config = OptimizationConfig::default();
let kernels =
SpecializedGpuKernels::new(config).expect("Failed to create specialized GPU kernels");
let mut state = vec![
Complex64::new(0.6, 0.0),
Complex64::new(0.0, 0.8),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
];
let original = state.clone();
// 2x2 identity on qubit 0.
let identity = vec![
Complex64::new(1.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(1.0, 0.0),
];
kernels
.apply_holonomic_gate(&mut state, &identity, &[QubitId(0)])
.expect("identity holonomic gate should succeed");
for (a, b) in state.iter().zip(original.iter()) {
assert!((a - b).norm() < 1e-12, "identity must not change the state");
}
}
#[test]
fn test_holonomic_gate_is_real_not_noop() {
// A Hadamard-like unitary on qubit 0 must actually transform |0> into an
// equal superposition. A no-op fabrication would leave the state at |0>.
let config = OptimizationConfig::default();
let kernels =
SpecializedGpuKernels::new(config).expect("Failed to create specialized GPU kernels");
let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
let h = vec![
Complex64::new(FRAC_1_SQRT_2, 0.0),
Complex64::new(FRAC_1_SQRT_2, 0.0),
Complex64::new(FRAC_1_SQRT_2, 0.0),
Complex64::new(-FRAC_1_SQRT_2, 0.0),
];
kernels
.apply_holonomic_gate(&mut state, &h, &[QubitId(0)])
.expect("hadamard holonomic gate should succeed");
// Both amplitudes must be 1/sqrt(2) — proving real computation occurred.
assert!((state[0].re - FRAC_1_SQRT_2).abs() < 1e-12);
assert!((state[1].re - FRAC_1_SQRT_2).abs() < 1e-12);
assert!(
(state[1].norm() - FRAC_1_SQRT_2).abs() < 1e-12,
"second amplitude must be populated; a no-op would leave it at 0"
);
}
#[test]
fn test_dense_gate_on_high_qubit_index() {
// Apply X to qubit 1 of a 2-qubit state |00> -> |10> (LSB ordering, so
// bit 1 set => basis index 2). Verifies correct subspace indexing.
let mut state = vec![
Complex64::new(1.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
Complex64::new(0.0, 0.0),
];
let x = vec![
Complex64::new(0.0, 0.0),
Complex64::new(1.0, 0.0),
Complex64::new(1.0, 0.0),
Complex64::new(0.0, 0.0),
];
apply_dense_gate_cpu(&mut state, &x, &[QubitId(1)]).expect("X on qubit 1 should succeed");
assert!(
(state[2].re - 1.0).abs() < 1e-12,
"amplitude should move to index 2"
);
assert!(state[0].norm() < 1e-12);
}
#[test]
fn test_dense_gate_dimension_mismatch_errors() {
let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
// 3-entry matrix is not a valid 2x2 — must error, not silently skip.
let bad = vec![Complex64::new(1.0, 0.0); 3];
assert!(apply_dense_gate_cpu(&mut state, &bad, &[QubitId(0)]).is_err());
}
#[test]
fn test_post_quantum_and_attention_are_honest_errors() {
// These specialized GPU ops are DEFERRED; they must return an honest
// error rather than a silent no-op success.
let kernels = SpecializedGpuKernels::new(OptimizationConfig::default())
.expect("kernel manager creation");
let mut state = vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)];
let pq = kernels.apply_post_quantum_hash_gate(
&mut state,
&[Complex64::new(1.0, 0.0)],
PostQuantumCompressionType::QuantumGrover { iterations: 1 },
);
assert!(
pq.is_err(),
"post-quantum hash gate must be an honest error"
);
let att = kernels.apply_quantum_ml_attention(
&mut state,
&[Complex64::new(1.0, 0.0)],
&[Complex64::new(1.0, 0.0)],
&[Complex64::new(1.0, 0.0)],
1,
);
assert!(att.is_err(), "quantum ML attention must be an honest error");
}
#[test]
fn test_compute_capability_is_not_hardcoded_75() {
// Real query: either a genuine capability (NOT the old fabricated (7,5))
// or an honest error when no device / no `gpu` feature. It must never
// silently return the fabricated (7, 5) constant.
match SpecializedGpuKernels::get_compute_capability() {
Ok(cc) => {
assert_ne!(
cc,
(7, 5),
"compute capability must be a real probe, not the fabricated (7,5)"
);
assert!(cc.0 >= 1, "real compute capability major must be >= 1");
}
Err(_) => {
// Honest error is acceptable when no GPU is present.
}
}
}
#[test]
fn test_performance_reporting() {
let config = OptimizationConfig::default();
let kernels = SpecializedGpuKernels::new(config)
.expect("Failed to create specialized GPU kernels for performance reporting");
let report = kernels.get_performance_report();
assert!(report.cache_hit_rate >= 0.0 && report.cache_hit_rate <= 1.0);
}
}