Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions qdp/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ cargo test --workspace
cd ..
```

**Encoding / pipeline dtype:** `qdp_core::Encoding::supports_f32` gates whether
`PipelineConfig::normalize()` keeps `dtype = Float32` for the synthetic pipeline. It reflects
**which encoders implement `encode_batch_f32` today** (currently amplitude only), not every
encoding that might eventually get a batch f32 path. When angle/basis gain real batch f32
support, widen `supports_f32` and adjust tests accordingly.

Run Python tests:

```bash
Expand Down
12 changes: 7 additions & 5 deletions qdp/qdp-core/src/encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use crate::dlpack::DLManagedTensor;
use crate::gpu::PipelineContext;
use crate::gpu::memory::{GpuStateVector, PinnedHostBuffer};
use crate::reader::StreamingDataReader;
use crate::types::Encoding;
use crate::{MahoutError, QdpEngine, Result};

/// 512MB staging buffer for large Parquet row groups (reduces fragmentation)
Expand Down Expand Up @@ -370,22 +371,23 @@ pub(crate) fn encode_from_parquet(
num_qubits: usize,
encoding_method: &str,
) -> Result<*mut DLManagedTensor> {
match encoding_method {
"amplitude" => {
let encoding = Encoding::from_str_ci(encoding_method)?;
match encoding {
Encoding::Amplitude => {
crate::profile_scope!("Mahout::EncodeAmplitudeFromParquet");
stream_encode(engine, path, num_qubits, amplitude::AmplitudeEncoder)
}
"angle" => {
Encoding::Angle => {
crate::profile_scope!("Mahout::EncodeAngleFromParquet");
stream_encode(engine, path, num_qubits, angle::AngleEncoder)
}
"basis" => {
Encoding::Basis => {
crate::profile_scope!("Mahout::EncodeBasisFromParquet");
stream_encode(engine, path, num_qubits, basis::BasisEncoder)
}
_ => Err(MahoutError::NotImplemented(format!(
"Encoding method '{}' not supported for streaming",
encoding_method
encoding.as_str()
))),
}
}
16 changes: 16 additions & 0 deletions qdp/qdp-core/src/gpu/encodings/iqp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::error::{MahoutError, Result};
use crate::gpu::memory::{GpuStateVector, Precision};
use cudarc::driver::CudaDevice;
use std::sync::Arc;
use std::sync::OnceLock;

#[cfg(target_os = "linux")]
use crate::gpu::memory::map_allocation_error;
Expand Down Expand Up @@ -405,3 +406,18 @@ impl QuantumEncoder for IqpEncoder {
}
}
}

static IQP_FULL: OnceLock<IqpEncoder> = OnceLock::new();
static IQP_Z_ONLY: OnceLock<IqpEncoder> = OnceLock::new();

/// Shared `'static` IQP encoder (full ZZ). Used by [`crate::Encoding::encoder`](crate::Encoding::encoder).
#[must_use]
pub fn iqp_full_encoder() -> &'static IqpEncoder {
IQP_FULL.get_or_init(IqpEncoder::full)
}

/// Shared `'static` IQP-Z encoder. Used by [`crate::Encoding::encoder`](crate::Encoding::encoder).
#[must_use]
pub fn iqp_z_encoder() -> &'static IqpEncoder {
IQP_Z_ONLY.get_or_init(IqpEncoder::z_only)
}
20 changes: 2 additions & 18 deletions qdp/qdp-core/src/gpu/encodings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn validate_qubit_count(num_qubits: usize) -> Result<()> {

/// Quantum encoding strategy interface
/// Implemented by: AmplitudeEncoder, AngleEncoder, BasisEncoder
pub trait QuantumEncoder: Send + Sync {
pub trait QuantumEncoder: Send + Sync + 'static {
/// Encode classical data to quantum state on GPU
fn encode(
&self,
Expand Down Expand Up @@ -181,21 +181,5 @@ pub mod phase;
pub use amplitude::AmplitudeEncoder;
pub use angle::AngleEncoder;
pub use basis::BasisEncoder;
pub use iqp::IqpEncoder;
pub use iqp::{IqpEncoder, iqp_full_encoder, iqp_z_encoder};
pub use phase::PhaseEncoder;

/// Create encoder by name: "amplitude", "angle", "basis", "iqp", or "iqp-z"
pub fn get_encoder(name: &str) -> Result<Box<dyn QuantumEncoder>> {
match name.to_lowercase().as_str() {
"amplitude" => Ok(Box::new(AmplitudeEncoder)),
"angle" => Ok(Box::new(AngleEncoder)),
"basis" => Ok(Box::new(BasisEncoder)),
"iqp" => Ok(Box::new(IqpEncoder::full())),
"iqp-z" => Ok(Box::new(IqpEncoder::z_only())),
"phase" => Ok(Box::new(PhaseEncoder)),
_ => Err(crate::error::MahoutError::InvalidInput(format!(
"Unknown encoder: {}. Available: amplitude, angle, basis, iqp, iqp-z, phase",
name
))),
}
}
2 changes: 1 addition & 1 deletion qdp/qdp-core/src/gpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub(crate) mod cuda_ffi;

#[cfg(target_os = "linux")]
pub use buffer_pool::{PinnedBufferHandle, PinnedBufferPool};
pub use encodings::{AmplitudeEncoder, AngleEncoder, BasisEncoder, QuantumEncoder, get_encoder};
pub use encodings::{AmplitudeEncoder, AngleEncoder, BasisEncoder, QuantumEncoder};
pub use memory::GpuStateVector;
pub use pipeline::run_dual_stream_pipeline;

Expand Down
55 changes: 46 additions & 9 deletions qdp/qdp-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ pub mod readers;
#[cfg(feature = "remote-io")]
pub mod remote;
pub mod tf_proto;
pub mod types;
#[macro_use]
mod profiling;

pub use error::{MahoutError, Result, cuda_error_to_string};
pub use gpu::memory::Precision;
pub use reader::{NullHandling, handle_float64_nulls};
pub use types::{Dtype, Encoding};

// Throughput/latency pipeline runner: single path using QdpEngine and encode_batch in Rust.
#[cfg(target_os = "linux")]
Expand All @@ -52,7 +54,6 @@ use std::ffi::c_void;
use std::sync::Arc;

use crate::dlpack::DLManagedTensor;
use crate::gpu::get_encoder;
use cudarc::driver::CudaDevice;

#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -160,7 +161,8 @@ impl QdpEngine {
) -> Result<*mut DLManagedTensor> {
crate::profile_scope!("Mahout::Encode");

let encoder = get_encoder(encoding_method)?;
let encoding = Encoding::from_str_ci(encoding_method)?;
let encoder = encoding.encoder();
let state_vector = encoder.encode(&self.device, data, num_qubits)?;
let state_vector = state_vector.to_precision(&self.device, self.precision)?;
let dlpack_ptr = {
Expand Down Expand Up @@ -205,10 +207,23 @@ impl QdpEngine {
sample_size: usize,
num_qubits: usize,
encoding_method: &str,
) -> Result<*mut DLManagedTensor> {
let encoding = Encoding::from_str_ci(encoding_method)?;
self.encode_batch_for_pipeline(batch_data, num_samples, sample_size, num_qubits, encoding)
}

/// Same as [`encode_batch`](Self::encode_batch) with a resolved [`Encoding`] (no string parse).
pub(crate) fn encode_batch_for_pipeline(
&self,
batch_data: &[f64],
num_samples: usize,
sample_size: usize,
num_qubits: usize,
encoding: Encoding,
) -> Result<*mut DLManagedTensor> {
crate::profile_scope!("Mahout::EncodeBatch");

let encoder = get_encoder(encoding_method)?;
let encoder = encoding.encoder();
let state_vector = encoder.encode_batch(
&self.device,
batch_data,
Expand All @@ -230,10 +245,29 @@ impl QdpEngine {
sample_size: usize,
num_qubits: usize,
encoding_method: &str,
) -> Result<*mut DLManagedTensor> {
let encoding = Encoding::from_str_ci(encoding_method)?;
self.encode_batch_f32_for_pipeline(
batch_data,
num_samples,
sample_size,
num_qubits,
encoding,
)
}

/// Same as [`encode_batch_f32`](Self::encode_batch_f32) with a resolved [`Encoding`].
pub(crate) fn encode_batch_f32_for_pipeline(
&self,
batch_data: &[f32],
num_samples: usize,
sample_size: usize,
num_qubits: usize,
encoding: Encoding,
) -> Result<*mut DLManagedTensor> {
crate::profile_scope!("Mahout::EncodeBatchF32");

let encoder = get_encoder(encoding_method)?;
let encoder = encoding.encoder();
let state_vector = encoder.encode_batch_f32(
&self.device,
batch_data,
Expand Down Expand Up @@ -263,8 +297,9 @@ impl QdpEngine {
encoding_method: &str,
) -> Result<()> {
crate::profile_scope!("Mahout::RunDualStreamEncode");
match encoding_method.to_lowercase().as_str() {
"amplitude" => {
let encoding = Encoding::from_str_ci(encoding_method)?;
match encoding {
Encoding::Amplitude => {
gpu::encodings::amplitude::AmplitudeEncoder::run_amplitude_dual_stream_pipeline(
&self.device,
host_data,
Expand All @@ -273,7 +308,7 @@ impl QdpEngine {
}
_ => Err(MahoutError::InvalidInput(format!(
"run_dual_stream_encode supports only 'amplitude' for now, got '{}'",
encoding_method
encoding.as_str()
))),
}
}
Expand Down Expand Up @@ -507,7 +542,8 @@ impl QdpEngine {

validate_cuda_input_ptr(&self.device, input_d)?;

let encoder = get_encoder(encoding_method)?;
let encoding = Encoding::from_str_ci(encoding_method)?;
let encoder = encoding.encoder();
let state_vector = unsafe {
encoder.encode_from_gpu_ptr(&self.device, input_d, input_len, num_qubits, stream)
}?;
Expand Down Expand Up @@ -841,7 +877,8 @@ impl QdpEngine {

validate_cuda_input_ptr(&self.device, input_batch_d)?;

let encoder = get_encoder(encoding_method)?;
let encoding = Encoding::from_str_ci(encoding_method)?;
let encoder = encoding.encoder();
let batch_state_vector = unsafe {
encoder.encode_batch_from_gpu_ptr(
&self.device,
Expand Down
Loading
Loading