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

richhuang 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 573e6b796 Refactor: Unify Qubit Validation Logic (#908)
573e6b796 is described below

commit 573e6b796c61fe9926fb98863edbdd224e92d514
Author: KUAN-HAO HUANG <[email protected]>
AuthorDate: Fri Jan 23 11:46:40 2026 +0800

    Refactor: Unify Qubit Validation Logic (#908)
---
 qdp/qdp-core/src/encoding/angle.rs          |  8 ++-----
 qdp/qdp-core/src/gpu/encodings/amplitude.rs |  2 +-
 qdp/qdp-core/src/gpu/encodings/angle.rs     | 21 +++---------------
 qdp/qdp-core/src/gpu/encodings/basis.rs     | 21 +++---------------
 qdp/qdp-core/src/gpu/encodings/mod.rs       | 33 ++++++++++++++++++++++++++++-
 qdp/qdp-core/src/preprocessing.rs           | 25 ++++++----------------
 qdp/qdp-kernels/src/kernel_config.h         |  7 ++++++
 7 files changed, 54 insertions(+), 63 deletions(-)

diff --git a/qdp/qdp-core/src/encoding/angle.rs 
b/qdp/qdp-core/src/encoding/angle.rs
index 0eac78d48..26b8af8a3 100644
--- a/qdp/qdp-core/src/encoding/angle.rs
+++ b/qdp/qdp-core/src/encoding/angle.rs
@@ -26,6 +26,7 @@ use qdp_kernels::launch_angle_encode_batch;
 
 use super::{ChunkEncoder, STAGE_SIZE_ELEMENTS};
 use crate::gpu::PipelineContext;
+use crate::gpu::encodings::validate_qubit_count;
 use crate::gpu::memory::PinnedHostBuffer;
 use crate::{MahoutError, QdpEngine, Result};
 
@@ -59,12 +60,7 @@ impl ChunkEncoder for AngleEncoder {
         sample_size: usize,
         num_qubits: usize,
     ) -> Result<Self::State> {
-        if num_qubits == 0 || num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} must be between 1 and 30",
-                num_qubits
-            )));
-        }
+        validate_qubit_count(num_qubits)?;
         if sample_size != num_qubits {
             return Err(MahoutError::InvalidInput(format!(
                 "Angle encoding expects sample_size={} (one angle per qubit), 
got {}",
diff --git a/qdp/qdp-core/src/gpu/encodings/amplitude.rs 
b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
index c20f0103f..34c486c57 100644
--- a/qdp/qdp-core/src/gpu/encodings/amplitude.rs
+++ b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
@@ -58,7 +58,7 @@ impl QuantumEncoder for AmplitudeEncoder {
         host_data: &[f64],
         num_qubits: usize,
     ) -> Result<GpuStateVector> {
-        // Validate qubits (max 30 = 16GB GPU memory)
+        // Validate qubits using Preprocessor (which uses validate_qubit_count 
internally)
         Preprocessor::validate_input(host_data, num_qubits)?;
         let state_len = 1 << num_qubits;
 
diff --git a/qdp/qdp-core/src/gpu/encodings/angle.rs 
b/qdp/qdp-core/src/gpu/encodings/angle.rs
index 44df2c810..769a7e96d 100644
--- a/qdp/qdp-core/src/gpu/encodings/angle.rs
+++ b/qdp/qdp-core/src/gpu/encodings/angle.rs
@@ -20,7 +20,7 @@
 // The compiler can't statically determine which path is taken.
 #![allow(unused_unsafe)]
 
-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};
@@ -137,12 +137,7 @@ impl QuantumEncoder for AngleEncoder {
             )));
         }
 
-        if num_qubits == 0 || num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} must be between 1 and 30",
-                num_qubits
-            )));
-        }
+        validate_qubit_count(num_qubits)?;
 
         for (i, &val) in batch_data.iter().enumerate() {
             if !val.is_finite() {
@@ -209,17 +204,7 @@ impl QuantumEncoder for AngleEncoder {
     }
 
     fn validate_input(&self, data: &[f64], num_qubits: usize) -> Result<()> {
-        if num_qubits == 0 {
-            return Err(MahoutError::InvalidInput(
-                "Number of qubits must be at least 1".to_string(),
-            ));
-        }
-        if num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} exceeds practical limit of 30",
-                num_qubits
-            )));
-        }
+        validate_qubit_count(num_qubits)?;
         if data.len() != num_qubits {
             return Err(MahoutError::InvalidInput(format!(
                 "Angle encoding expects {} values (one per qubit), got {}",
diff --git a/qdp/qdp-core/src/gpu/encodings/basis.rs 
b/qdp/qdp-core/src/gpu/encodings/basis.rs
index 2e6169ade..0b24f9796 100644
--- a/qdp/qdp-core/src/gpu/encodings/basis.rs
+++ b/qdp/qdp-core/src/gpu/encodings/basis.rs
@@ -20,7 +20,7 @@
 // The compiler can't statically determine which path is taken.
 #![allow(unused_unsafe)]
 
-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};
@@ -152,12 +152,7 @@ impl QuantumEncoder for BasisEncoder {
             )));
         }
 
-        if num_qubits == 0 || num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} must be between 1 and 30",
-                num_qubits
-            )));
-        }
+        validate_qubit_count(num_qubits)?;
 
         let state_len = 1 << num_qubits;
 
@@ -232,17 +227,7 @@ impl QuantumEncoder for BasisEncoder {
 
     fn validate_input(&self, data: &[f64], num_qubits: usize) -> Result<()> {
         // Basic validation: qubits and data availability
-        if num_qubits == 0 {
-            return Err(MahoutError::InvalidInput(
-                "Number of qubits must be at least 1".to_string(),
-            ));
-        }
-        if num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} exceeds practical limit of 30",
-                num_qubits
-            )));
-        }
+        validate_qubit_count(num_qubits)?;
         if data.is_empty() {
             return Err(MahoutError::InvalidInput(
                 "Input data cannot be empty".to_string(),
diff --git a/qdp/qdp-core/src/gpu/encodings/mod.rs 
b/qdp/qdp-core/src/gpu/encodings/mod.rs
index 295e09503..63c6addca 100644
--- a/qdp/qdp-core/src/gpu/encodings/mod.rs
+++ b/qdp/qdp-core/src/gpu/encodings/mod.rs
@@ -18,11 +18,42 @@
 
 use std::sync::Arc;
 
-use crate::error::Result;
+use crate::error::{MahoutError, Result};
 use crate::gpu::memory::GpuStateVector;
 use crate::preprocessing::Preprocessor;
 use cudarc::driver::CudaDevice;
 
+/// Maximum number of qubits supported (16GB GPU memory limit)
+/// This constant must match MAX_QUBITS in qdp-kernels/src/kernel_config.h
+pub const MAX_QUBITS: usize = 30;
+
+/// Validates qubit count against practical limits.
+///
+/// Checks:
+/// - Qubit count is at least 1
+/// - Qubit count does not exceed MAX_QUBITS
+///
+/// # Arguments
+/// * `num_qubits` - The number of qubits to validate
+///
+/// # Returns
+/// * `Ok(())` if the qubit count is valid
+/// * `Err(MahoutError::InvalidInput)` if the qubit count is invalid
+pub fn validate_qubit_count(num_qubits: usize) -> Result<()> {
+    if num_qubits == 0 {
+        return Err(MahoutError::InvalidInput(
+            "Number of qubits must be at least 1".to_string(),
+        ));
+    }
+    if num_qubits > MAX_QUBITS {
+        return Err(MahoutError::InvalidInput(format!(
+            "Number of qubits {} exceeds practical limit of {}",
+            num_qubits, MAX_QUBITS
+        )));
+    }
+    Ok(())
+}
+
 /// Quantum encoding strategy interface
 /// Implemented by: AmplitudeEncoder, AngleEncoder, BasisEncoder
 pub trait QuantumEncoder: Send + Sync {
diff --git a/qdp/qdp-core/src/preprocessing.rs 
b/qdp/qdp-core/src/preprocessing.rs
index 0369f6f62..c8469aa39 100644
--- a/qdp/qdp-core/src/preprocessing.rs
+++ b/qdp/qdp-core/src/preprocessing.rs
@@ -15,6 +15,7 @@
 // limitations under the License.
 
 use crate::error::{MahoutError, Result};
+use crate::gpu::encodings::validate_qubit_count;
 use rayon::prelude::*;
 
 /// Shared CPU-based pre-processing pipeline for quantum encoding.
@@ -27,22 +28,12 @@ impl Preprocessor {
     /// Validates standard quantum input constraints.
     ///
     /// Checks:
-    /// - Qubit count within practical limits (1-30)
+    /// - Qubit count within practical limits (1-MAX_QUBITS)
     /// - Data availability
     /// - Data length against state vector size
     pub fn validate_input(host_data: &[f64], num_qubits: usize) -> Result<()> {
-        // Validate qubits (max 30 = 16GB GPU memory)
-        if num_qubits == 0 {
-            return Err(MahoutError::InvalidInput(
-                "Number of qubits must be at least 1".to_string(),
-            ));
-        }
-        if num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} exceeds practical limit of 30",
-                num_qubits
-            )));
-        }
+        // Validate qubits using shared validation function (max MAX_QUBITS = 
16GB GPU memory)
+        validate_qubit_count(num_qubits)?;
 
         // Validate input data
         if host_data.is_empty() {
@@ -116,12 +107,8 @@ impl Preprocessor {
             )));
         }
 
-        if num_qubits == 0 || num_qubits > 30 {
-            return Err(MahoutError::InvalidInput(format!(
-                "Number of qubits {} must be between 1 and 30",
-                num_qubits
-            )));
-        }
+        // Validate qubits using shared validation function
+        validate_qubit_count(num_qubits)?;
 
         let state_len = 1 << num_qubits;
         if sample_size > state_len {
diff --git a/qdp/qdp-kernels/src/kernel_config.h 
b/qdp/qdp-kernels/src/kernel_config.h
index 4b4795520..b00ef169f 100644
--- a/qdp/qdp-kernels/src/kernel_config.h
+++ b/qdp/qdp-kernels/src/kernel_config.h
@@ -50,6 +50,13 @@
 // This is a hardware limitation, not a tunable parameter
 #define CUDA_MAX_GRID_DIM_1D 65535
 
+// ============================================================================
+// Qubit Limits
+// ============================================================================
+// Maximum qubits supported (16GB GPU memory limit)
+// This limit ensures state vectors fit within practical GPU memory constraints
+#define MAX_QUBITS 30
+
 // ============================================================================
 // Convenience Macros
 // ============================================================================

Reply via email to