This is an automated email from the ASF dual-hosted git repository.

viiccwen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git


The following commit(s) were added to refs/heads/main by this push:
     new b9e33e662 fix(qdp): apply shared max qubit validation (#1442)
b9e33e662 is described below

commit b9e33e662ef76557ffbeba18b4ddcec852c4e9b5
Author: Vic Wen <[email protected]>
AuthorDate: Thu Jul 16 16:19:52 2026 +0800

    fix(qdp): apply shared max qubit validation (#1442)
---
 qdp/qdp-core/src/gpu/encodings/amplitude.rs |  8 ++++-
 qdp/qdp-core/src/gpu/encodings/mod.rs       |  2 +-
 qdp/qdp-core/tests/gpu_ptr_encoding.rs      | 53 +++++++++++++++++++++++++++++
 qdp/qdp-core/tests/gpu_validation.rs        | 10 ++++++
 qdp/qdp-kernels/src/kernel_config.h         |  7 ----
 5 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/qdp/qdp-core/src/gpu/encodings/amplitude.rs 
b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
index 7cf70d9ec..7c8d61490 100644
--- a/qdp/qdp-core/src/gpu/encodings/amplitude.rs
+++ b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
@@ -22,7 +22,7 @@
 
 use std::sync::Arc;
 
-use super::QuantumEncoder;
+use super::{QuantumEncoder, validate_qubit_count};
 #[cfg(target_os = "linux")]
 use crate::error::cuda_error_to_string;
 use crate::error::{MahoutError, Result};
@@ -308,6 +308,7 @@ impl QuantumEncoder for AmplitudeEncoder {
         num_qubits: usize,
         stream: *mut c_void,
     ) -> Result<GpuStateVector> {
+        validate_qubit_count(num_qubits)?;
         let state_len = 1 << num_qubits;
         if input_len == 0 {
             return Err(MahoutError::InvalidInput(
@@ -371,6 +372,7 @@ impl QuantumEncoder for AmplitudeEncoder {
         num_qubits: usize,
         stream: *mut c_void,
     ) -> Result<GpuStateVector> {
+        validate_qubit_count(num_qubits)?;
         let state_len = 1 << num_qubits;
         if sample_size == 0 {
             return Err(MahoutError::InvalidInput(
@@ -469,6 +471,7 @@ impl QuantumEncoder for AmplitudeEncoder {
     ) -> Result<GpuStateVector> {
         crate::profile_scope!("AmplitudeEncoder::encode_batch_f32");
 
+        validate_qubit_count(num_qubits)?;
         let state_len = 1 << num_qubits;
 
         if sample_size == 0 {
@@ -603,6 +606,7 @@ impl QuantumEncoder for AmplitudeEncoder {
         num_qubits: usize,
         stream: *mut c_void,
     ) -> Result<GpuStateVector> {
+        validate_qubit_count(num_qubits)?;
         let state_len = 1 << num_qubits;
         if sample_size == 0 {
             return Err(MahoutError::InvalidInput(
@@ -859,6 +863,7 @@ impl AmplitudeEncoder {
             ));
         }
 
+        validate_qubit_count(num_qubits)?;
         let state_len = 1usize << num_qubits;
         if input_len > state_len {
             return Err(MahoutError::InvalidInput(format!(
@@ -928,6 +933,7 @@ impl AmplitudeEncoder {
         num_qubits: usize,
         stream: *mut c_void,
     ) -> Result<GpuStateVector> {
+        validate_qubit_count(num_qubits)?;
         let state_len = 1 << num_qubits;
         if num_samples == 0 {
             return Err(MahoutError::InvalidInput(
diff --git a/qdp/qdp-core/src/gpu/encodings/mod.rs 
b/qdp/qdp-core/src/gpu/encodings/mod.rs
index 8d0fd5b4c..787b631e5 100644
--- a/qdp/qdp-core/src/gpu/encodings/mod.rs
+++ b/qdp/qdp-core/src/gpu/encodings/mod.rs
@@ -26,7 +26,7 @@ use cudarc::driver::CudaDevice;
 use std::ffi::c_void;
 
 /// Maximum number of qubits supported (16GB GPU memory limit)
-/// This constant must match MAX_QUBITS in qdp-kernels/src/kernel_config.h
+/// Shared by all QDP encoder validation paths.
 pub const MAX_QUBITS: usize = 30;
 
 /// Validates qubit count against practical limits.
diff --git a/qdp/qdp-core/tests/gpu_ptr_encoding.rs 
b/qdp/qdp-core/tests/gpu_ptr_encoding.rs
index 48ba65f84..f9396e1d4 100644
--- a/qdp/qdp-core/tests/gpu_ptr_encoding.rs
+++ b/qdp/qdp-core/tests/gpu_ptr_encoding.rs
@@ -19,6 +19,8 @@
 #![cfg(target_os = "linux")]
 
 use cudarc::driver::{DevicePtr, DeviceSlice};
+use qdp_core::gpu::encodings::MAX_QUBITS;
+use qdp_core::gpu::{AmplitudeEncoder, QuantumEncoder};
 use qdp_core::{MahoutError, Precision, QdpEngine};
 use std::ffi::c_void;
 
@@ -40,8 +42,59 @@ fn engine_f32() -> Option<QdpEngine> {
     common::qdp_engine_with_precision(Precision::Float32)
 }
 
+fn assert_max_qubits_error<T>(result: qdp_core::Result<T>) {
+    assert!(
+        matches!(result, Err(MahoutError::InvalidInput(msg)) if
+            msg.contains("exceeds") && msg.contains(&MAX_QUBITS.to_string())),
+        "amplitude GPU-pointer path should use the shared qubit limit"
+    );
+}
+
 // ---- Validation / error-path tests (return before using pointer) ----
 
+#[test]
+fn test_amplitude_gpu_pointer_paths_reject_excessive_qubits() {
+    let Some(engine) = common::qdp_engine() else {
+        return;
+    };
+
+    let Some((_f64_device, f64_data_d)) = common::copy_f64_to_device(&[1.0]) 
else {
+        return;
+    };
+    let Some((f32_device, f32_data_d)) = 
common::copy_f32_to_device(&[1.0_f32]) else {
+        return;
+    };
+    let f64_ptr = *f64_data_d.device_ptr() as *const f64 as *const c_void;
+    let f32_ptr = *f32_data_d.device_ptr() as *const f32;
+
+    // Use the platform word size so a missing validation call fails at the 
shift without
+    // attempting an enormous GPU allocation.
+    let excessive_qubits = usize::BITS as usize;
+
+    assert_max_qubits_error(unsafe {
+        engine.encode_from_gpu_ptr(f64_ptr, 1, excessive_qubits, "amplitude")
+    });
+    assert_max_qubits_error(unsafe {
+        engine.encode_batch_from_gpu_ptr(f64_ptr, 1, 1, excessive_qubits, 
"amplitude")
+    });
+    assert_max_qubits_error(unsafe {
+        engine.encode_from_gpu_ptr_f32(f32_ptr, 1, excessive_qubits)
+    });
+    assert_max_qubits_error(unsafe {
+        engine.encode_batch_from_gpu_ptr_f32(f32_ptr, 1, 1, excessive_qubits)
+    });
+    assert_max_qubits_error(unsafe {
+        AmplitudeEncoder.encode_batch_from_gpu_ptr_f32(
+            &f32_device,
+            f32_ptr as *const c_void,
+            1,
+            1,
+            excessive_qubits,
+            std::ptr::null_mut(),
+        )
+    });
+}
+
 #[test]
 fn test_encode_from_gpu_ptr_unknown_method() {
     let Some(engine) = common::qdp_engine() else {
diff --git a/qdp/qdp-core/tests/gpu_validation.rs 
b/qdp/qdp-core/tests/gpu_validation.rs
index 291f92dce..74becfccf 100644
--- a/qdp/qdp-core/tests/gpu_validation.rs
+++ b/qdp/qdp-core/tests/gpu_validation.rs
@@ -127,6 +127,16 @@ fn test_input_validation_max_qubits() {
         }
         _ => panic!("Expected InvalidInput error for max qubits"),
     }
+
+    // Use the platform word size so a missing validation call fails at the 
shift without
+    // attempting an enormous GPU allocation.
+    let excessive_qubits = usize::BITS as usize;
+    let result = engine.encode_batch_f32(&[1.0_f32], 1, 1, excessive_qubits, 
"amplitude");
+    assert!(
+        matches!(result, Err(MahoutError::InvalidInput(msg)) if
+            msg.contains("exceeds") && msg.contains(&MAX_QUBITS.to_string())),
+        "f32 batch path should use the shared qubit limit"
+    );
 }
 
 #[test]
diff --git a/qdp/qdp-kernels/src/kernel_config.h 
b/qdp/qdp-kernels/src/kernel_config.h
index 9a5708ac3..069f69a3b 100644
--- a/qdp/qdp-kernels/src/kernel_config.h
+++ b/qdp/qdp-kernels/src/kernel_config.h
@@ -50,13 +50,6 @@
 // This is a hardware limitation, not a tunable parameter
 #define CUDA_MAX_GRID_DIM_1D 2147483647
 
-// ============================================================================
-// Qubit Limits
-// ============================================================================
-// Maximum qubits supported (16GB GPU memory limit)
-// This limit ensures state vectors fit within practical GPU memory constraints
-#define MAX_QUBITS 30
-
 // ============================================================================
 // FWT (Fast Walsh-Hadamard Transform) Configuration
 // ============================================================================

Reply via email to