Skip to content

Commit 573e6b7

Browse files
authored
Refactor: Unify Qubit Validation Logic (#908)
1 parent 187dc4b commit 573e6b7

File tree

7 files changed

+54
-63
lines changed

7 files changed

+54
-63
lines changed

qdp/qdp-core/src/encoding/angle.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use qdp_kernels::launch_angle_encode_batch;
2626

2727
use super::{ChunkEncoder, STAGE_SIZE_ELEMENTS};
2828
use crate::gpu::PipelineContext;
29+
use crate::gpu::encodings::validate_qubit_count;
2930
use crate::gpu::memory::PinnedHostBuffer;
3031
use crate::{MahoutError, QdpEngine, Result};
3132

@@ -59,12 +60,7 @@ impl ChunkEncoder for AngleEncoder {
5960
sample_size: usize,
6061
num_qubits: usize,
6162
) -> Result<Self::State> {
62-
if num_qubits == 0 || num_qubits > 30 {
63-
return Err(MahoutError::InvalidInput(format!(
64-
"Number of qubits {} must be between 1 and 30",
65-
num_qubits
66-
)));
67-
}
63+
validate_qubit_count(num_qubits)?;
6864
if sample_size != num_qubits {
6965
return Err(MahoutError::InvalidInput(format!(
7066
"Angle encoding expects sample_size={} (one angle per qubit), got {}",

qdp/qdp-core/src/gpu/encodings/amplitude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl QuantumEncoder for AmplitudeEncoder {
5858
host_data: &[f64],
5959
num_qubits: usize,
6060
) -> Result<GpuStateVector> {
61-
// Validate qubits (max 30 = 16GB GPU memory)
61+
// Validate qubits using Preprocessor (which uses validate_qubit_count internally)
6262
Preprocessor::validate_input(host_data, num_qubits)?;
6363
let state_len = 1 << num_qubits;
6464

qdp/qdp-core/src/gpu/encodings/angle.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// The compiler can't statically determine which path is taken.
2121
#![allow(unused_unsafe)]
2222

23-
use super::QuantumEncoder;
23+
use super::{QuantumEncoder, validate_qubit_count};
2424
#[cfg(target_os = "linux")]
2525
use crate::error::cuda_error_to_string;
2626
use crate::error::{MahoutError, Result};
@@ -137,12 +137,7 @@ impl QuantumEncoder for AngleEncoder {
137137
)));
138138
}
139139

140-
if num_qubits == 0 || num_qubits > 30 {
141-
return Err(MahoutError::InvalidInput(format!(
142-
"Number of qubits {} must be between 1 and 30",
143-
num_qubits
144-
)));
145-
}
140+
validate_qubit_count(num_qubits)?;
146141

147142
for (i, &val) in batch_data.iter().enumerate() {
148143
if !val.is_finite() {
@@ -209,17 +204,7 @@ impl QuantumEncoder for AngleEncoder {
209204
}
210205

211206
fn validate_input(&self, data: &[f64], num_qubits: usize) -> Result<()> {
212-
if num_qubits == 0 {
213-
return Err(MahoutError::InvalidInput(
214-
"Number of qubits must be at least 1".to_string(),
215-
));
216-
}
217-
if num_qubits > 30 {
218-
return Err(MahoutError::InvalidInput(format!(
219-
"Number of qubits {} exceeds practical limit of 30",
220-
num_qubits
221-
)));
222-
}
207+
validate_qubit_count(num_qubits)?;
223208
if data.len() != num_qubits {
224209
return Err(MahoutError::InvalidInput(format!(
225210
"Angle encoding expects {} values (one per qubit), got {}",

qdp/qdp-core/src/gpu/encodings/basis.rs

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// The compiler can't statically determine which path is taken.
2121
#![allow(unused_unsafe)]
2222

23-
use super::QuantumEncoder;
23+
use super::{QuantumEncoder, validate_qubit_count};
2424
#[cfg(target_os = "linux")]
2525
use crate::error::cuda_error_to_string;
2626
use crate::error::{MahoutError, Result};
@@ -152,12 +152,7 @@ impl QuantumEncoder for BasisEncoder {
152152
)));
153153
}
154154

155-
if num_qubits == 0 || num_qubits > 30 {
156-
return Err(MahoutError::InvalidInput(format!(
157-
"Number of qubits {} must be between 1 and 30",
158-
num_qubits
159-
)));
160-
}
155+
validate_qubit_count(num_qubits)?;
161156

162157
let state_len = 1 << num_qubits;
163158

@@ -232,17 +227,7 @@ impl QuantumEncoder for BasisEncoder {
232227

233228
fn validate_input(&self, data: &[f64], num_qubits: usize) -> Result<()> {
234229
// Basic validation: qubits and data availability
235-
if num_qubits == 0 {
236-
return Err(MahoutError::InvalidInput(
237-
"Number of qubits must be at least 1".to_string(),
238-
));
239-
}
240-
if num_qubits > 30 {
241-
return Err(MahoutError::InvalidInput(format!(
242-
"Number of qubits {} exceeds practical limit of 30",
243-
num_qubits
244-
)));
245-
}
230+
validate_qubit_count(num_qubits)?;
246231
if data.is_empty() {
247232
return Err(MahoutError::InvalidInput(
248233
"Input data cannot be empty".to_string(),

qdp/qdp-core/src/gpu/encodings/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,42 @@
1818

1919
use std::sync::Arc;
2020

21-
use crate::error::Result;
21+
use crate::error::{MahoutError, Result};
2222
use crate::gpu::memory::GpuStateVector;
2323
use crate::preprocessing::Preprocessor;
2424
use cudarc::driver::CudaDevice;
2525

26+
/// Maximum number of qubits supported (16GB GPU memory limit)
27+
/// This constant must match MAX_QUBITS in qdp-kernels/src/kernel_config.h
28+
pub const MAX_QUBITS: usize = 30;
29+
30+
/// Validates qubit count against practical limits.
31+
///
32+
/// Checks:
33+
/// - Qubit count is at least 1
34+
/// - Qubit count does not exceed MAX_QUBITS
35+
///
36+
/// # Arguments
37+
/// * `num_qubits` - The number of qubits to validate
38+
///
39+
/// # Returns
40+
/// * `Ok(())` if the qubit count is valid
41+
/// * `Err(MahoutError::InvalidInput)` if the qubit count is invalid
42+
pub fn validate_qubit_count(num_qubits: usize) -> Result<()> {
43+
if num_qubits == 0 {
44+
return Err(MahoutError::InvalidInput(
45+
"Number of qubits must be at least 1".to_string(),
46+
));
47+
}
48+
if num_qubits > MAX_QUBITS {
49+
return Err(MahoutError::InvalidInput(format!(
50+
"Number of qubits {} exceeds practical limit of {}",
51+
num_qubits, MAX_QUBITS
52+
)));
53+
}
54+
Ok(())
55+
}
56+
2657
/// Quantum encoding strategy interface
2758
/// Implemented by: AmplitudeEncoder, AngleEncoder, BasisEncoder
2859
pub trait QuantumEncoder: Send + Sync {

qdp/qdp-core/src/preprocessing.rs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// limitations under the License.
1616

1717
use crate::error::{MahoutError, Result};
18+
use crate::gpu::encodings::validate_qubit_count;
1819
use rayon::prelude::*;
1920

2021
/// Shared CPU-based pre-processing pipeline for quantum encoding.
@@ -27,22 +28,12 @@ impl Preprocessor {
2728
/// Validates standard quantum input constraints.
2829
///
2930
/// Checks:
30-
/// - Qubit count within practical limits (1-30)
31+
/// - Qubit count within practical limits (1-MAX_QUBITS)
3132
/// - Data availability
3233
/// - Data length against state vector size
3334
pub fn validate_input(host_data: &[f64], num_qubits: usize) -> Result<()> {
34-
// Validate qubits (max 30 = 16GB GPU memory)
35-
if num_qubits == 0 {
36-
return Err(MahoutError::InvalidInput(
37-
"Number of qubits must be at least 1".to_string(),
38-
));
39-
}
40-
if num_qubits > 30 {
41-
return Err(MahoutError::InvalidInput(format!(
42-
"Number of qubits {} exceeds practical limit of 30",
43-
num_qubits
44-
)));
45-
}
35+
// Validate qubits using shared validation function (max MAX_QUBITS = 16GB GPU memory)
36+
validate_qubit_count(num_qubits)?;
4637

4738
// Validate input data
4839
if host_data.is_empty() {
@@ -116,12 +107,8 @@ impl Preprocessor {
116107
)));
117108
}
118109

119-
if num_qubits == 0 || num_qubits > 30 {
120-
return Err(MahoutError::InvalidInput(format!(
121-
"Number of qubits {} must be between 1 and 30",
122-
num_qubits
123-
)));
124-
}
110+
// Validate qubits using shared validation function
111+
validate_qubit_count(num_qubits)?;
125112

126113
let state_len = 1 << num_qubits;
127114
if sample_size > state_len {

qdp/qdp-kernels/src/kernel_config.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@
5050
// This is a hardware limitation, not a tunable parameter
5151
#define CUDA_MAX_GRID_DIM_1D 65535
5252

53+
// ============================================================================
54+
// Qubit Limits
55+
// ============================================================================
56+
// Maximum qubits supported (16GB GPU memory limit)
57+
// This limit ensures state vectors fit within practical GPU memory constraints
58+
#define MAX_QUBITS 30
59+
5360
// ============================================================================
5461
// Convenience Macros
5562
// ============================================================================

0 commit comments

Comments
 (0)