Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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