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
// ============================================================================