This is an automated email from the ASF dual-hosted git repository.
guanmingchiu pushed a commit to branch dev-qdp
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/dev-qdp by this push:
new e87682390 [QDP] Add Python bindings for QDP using PyO3 (#649)
e87682390 is described below
commit e87682390aabb3cc5bcf863fd1dfe8d1e78bb146
Author: Guan-Ming (Wesley) Chiu <[email protected]>
AuthorDate: Sat Nov 29 20:13:18 2025 +0800
[QDP] Add Python bindings for QDP using PyO3 (#649)
* Add Python bindings for QDP using PyO3
* Add QuantumTensor class for DLPack integration
* Add TODO
* Update qdp/qdp-python/src/lib.rs
Co-authored-by: Ryan Huang <[email protected]>
---------
Co-authored-by: Ryan Huang <[email protected]>
---
.github/workflows/pre-commit.yml | 4 +-
.github/workflows/python-bindings.yml | 35 +++
qdp/Cargo.lock | 315 +++++++++++++++++++++
qdp/Cargo.toml | 5 +-
qdp/qdp-core/.gitignore | 1 -
qdp/qdp-core/src/dlpack.rs | 9 +-
qdp/qdp-core/src/error.rs | 1 -
qdp/qdp-core/src/gpu/encodings/amplitude.rs | 7 +-
qdp/qdp-core/src/gpu/encodings/angle.rs | 1 -
qdp/qdp-core/src/gpu/encodings/basis.rs | 1 -
qdp/qdp-core/src/gpu/encodings/mod.rs | 1 -
qdp/qdp-core/src/gpu/memory.rs | 16 +-
qdp/qdp-core/src/gpu/mod.rs | 1 -
qdp/qdp-core/src/lib.rs | 14 +-
qdp/qdp-kernels/build.rs | 17 +-
qdp/qdp-kernels/src/amplitude.cu | 9 +-
qdp/qdp-kernels/src/lib.rs | 3 +-
qdp/qdp-python/.gitignore | 72 +++++
qdp/qdp-python/Cargo.toml | 5 +-
qdp/qdp-python/README.md | 49 ++++
qdp/qdp-python/pyproject.toml | 32 +++
qdp/qdp-python/src/lib.rs | 172 ++++++++++++
qdp/qdp-python/tests/test_bindings.py | 91 ++++++
qdp/qdp-python/uv.lock | 422 ++++++++++++++++++++++++++++
24 files changed, 1228 insertions(+), 55 deletions(-)
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 69dd15a2c..c4670c65b 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -17,9 +17,9 @@ name: Pre-commit
on:
push:
- branches: [main]
+ branches: [main, dev-qdp]
pull_request:
- branches: [main]
+ branches: [main, dev-qdp]
jobs:
test:
diff --git a/.github/workflows/python-bindings.yml
b/.github/workflows/python-bindings.yml
new file mode 100644
index 000000000..71bddb17a
--- /dev/null
+++ b/.github/workflows/python-bindings.yml
@@ -0,0 +1,35 @@
+name: Python Bindings
+
+on:
+ push:
+ branches:
+ - dev-qdp
+ pull_request:
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Set up uv
+ uses: astral-sh/setup-uv@v7
+ with:
+ enable-cache: true
+ python-version: '3.11'
+
+ - name: Build PyO3 bindings
+ working-directory: qdp/qdp-python
+ run: |
+ uv sync --group dev
+ uv run maturin develop
+
+ - name: Upload wheel
+ uses: actions/upload-artifact@v4
+ with:
+ name: python-wheel
+ path: qdp/qdp-python/target/wheels/*.whl
diff --git a/qdp/Cargo.lock b/qdp/Cargo.lock
new file mode 100644
index 000000000..f19b8ac3a
--- /dev/null
+++ b/qdp/Cargo.lock
@@ -0,0 +1,315 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "cc"
+version = "1.2.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "cudarc"
+version = "0.13.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "486c221362668c63a1636cfa51463b09574433b39029326cff40864b3ba12b6e"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "indoc"
+version = "2.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf"
+dependencies = [
+ "indoc",
+ "libc",
+ "memoffset",
+ "once_cell",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb"
+dependencies = [
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "pyo3-build-config",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "qdp-core"
+version = "0.1.0"
+dependencies = [
+ "cudarc",
+ "qdp-kernels",
+ "rayon",
+ "thiserror",
+]
+
+[[package]]
+name = "qdp-kernels"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "cudarc",
+]
+
+[[package]]
+name = "qdp-python"
+version = "0.1.0"
+dependencies = [
+ "pyo3",
+ "qdp-core",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "syn"
+version = "2.0.111"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c"
+
+[[package]]
+name = "thiserror"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unindent"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
diff --git a/qdp/Cargo.toml b/qdp/Cargo.toml
index 408183cda..982b15c1d 100644
--- a/qdp/Cargo.toml
+++ b/qdp/Cargo.toml
@@ -2,8 +2,7 @@
members = [
"qdp-core",
"qdp-kernels",
- # TODO: Python bindings (add later)
- # "qdp-python",
+ "qdp-python",
]
resolver = "2"
@@ -25,5 +24,3 @@ cc = "1.2"
thiserror = "2.0"
# Parallel computing (for CPU preprocessing)
rayon = "1.10"
-
-
diff --git a/qdp/qdp-core/.gitignore b/qdp/qdp-core/.gitignore
index 8b1378917..e69de29bb 100644
--- a/qdp/qdp-core/.gitignore
+++ b/qdp/qdp-core/.gitignore
@@ -1 +0,0 @@
-
diff --git a/qdp/qdp-core/src/dlpack.rs b/qdp/qdp-core/src/dlpack.rs
index cd05cb696..b31ba0603 100644
--- a/qdp/qdp-core/src/dlpack.rs
+++ b/qdp/qdp-core/src/dlpack.rs
@@ -59,7 +59,7 @@ pub struct DLManagedTensor {
// Deleter: frees memory when PyTorch is done
/// Called by PyTorch to free tensor memory
-///
+///
/// # Safety
/// Frees shape, strides, GPU buffer, and managed tensor.
/// Caller must ensure the pointer is valid and points to a properly
initialized DLManagedTensor.
@@ -70,7 +70,7 @@ pub unsafe extern "C" fn dlpack_deleter(managed: *mut
DLManagedTensor) {
}
let tensor = &(*managed).dl_tensor;
-
+
// 1. Free shape array (Box<[i64]>)
if !tensor.shape.is_null() {
let len = if tensor.ndim > 0 { tensor.ndim as usize } else { 1 };
@@ -97,9 +97,9 @@ pub unsafe extern "C" fn dlpack_deleter(managed: *mut
DLManagedTensor) {
impl GpuStateVector {
/// Convert to DLPack format for PyTorch
- ///
+ ///
/// Returns raw pointer for torch.from_dlpack() (zero-copy, GPU memory).
- ///
+ ///
/// # Safety
/// Freed by DLPack deleter when PyTorch releases tensor.
/// Do not free manually.
@@ -141,4 +141,3 @@ impl GpuStateVector {
Box::into_raw(Box::new(managed))
}
}
-
diff --git a/qdp/qdp-core/src/error.rs b/qdp/qdp-core/src/error.rs
index 5c8d4dc75..db57d948d 100644
--- a/qdp/qdp-core/src/error.rs
+++ b/qdp/qdp-core/src/error.rs
@@ -21,4 +21,3 @@ pub enum MahoutError {
/// Result type alias for Mahout operations
pub type Result<T> = std::result::Result<T, MahoutError>;
-
diff --git a/qdp/qdp-core/src/gpu/encodings/amplitude.rs
b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
index fecaf1dff..761656821 100644
--- a/qdp/qdp-core/src/gpu/encodings/amplitude.rs
+++ b/qdp/qdp-core/src/gpu/encodings/amplitude.rs
@@ -15,7 +15,7 @@ use cudarc::driver::{CudaSlice, DevicePtr};
use qdp_kernels::launch_amplitude_encode;
/// Amplitude encoding: data → normalized quantum amplitudes
-///
+///
/// Steps: L2 norm (CPU) → GPU allocation → CUDA kernel (normalize + pad)
/// Fast: ~50-100x vs circuit-based methods
pub struct AmplitudeEncoder;
@@ -56,7 +56,7 @@ impl QuantumEncoder for AmplitudeEncoder {
// Calculate L2 norm (parallel on CPU for speed)
let norm_sq: f64 = host_data.par_iter().map(|x| x * x).sum();
let norm = norm_sq.sqrt();
-
+
if norm == 0.0 {
return Err(MahoutError::InvalidInput("Input data has zero
norm".to_string()));
}
@@ -94,7 +94,7 @@ impl QuantumEncoder for AmplitudeEncoder {
Ok(state_vector)
}
-
+
#[cfg(not(target_os = "linux"))]
{
Err(MahoutError::Cuda("CUDA unavailable (non-Linux)".to_string()))
@@ -128,4 +128,3 @@ fn cuda_error_to_string(code: i32) -> &'static str {
_ => "Unknown CUDA error",
}
}
-
diff --git a/qdp/qdp-core/src/gpu/encodings/angle.rs
b/qdp/qdp-core/src/gpu/encodings/angle.rs
index 0404599ea..92d7f4e34 100644
--- a/qdp/qdp-core/src/gpu/encodings/angle.rs
+++ b/qdp/qdp-core/src/gpu/encodings/angle.rs
@@ -31,4 +31,3 @@ impl QuantumEncoder for AngleEncoder {
"Angle encoding (not implemented)"
}
}
-
diff --git a/qdp/qdp-core/src/gpu/encodings/basis.rs
b/qdp/qdp-core/src/gpu/encodings/basis.rs
index bd01cbad0..72c0217aa 100644
--- a/qdp/qdp-core/src/gpu/encodings/basis.rs
+++ b/qdp/qdp-core/src/gpu/encodings/basis.rs
@@ -31,4 +31,3 @@ impl QuantumEncoder for BasisEncoder {
"Basis encoding (not implemented)"
}
}
-
diff --git a/qdp/qdp-core/src/gpu/encodings/mod.rs
b/qdp/qdp-core/src/gpu/encodings/mod.rs
index e06b20703..6f6e987ca 100644
--- a/qdp/qdp-core/src/gpu/encodings/mod.rs
+++ b/qdp/qdp-core/src/gpu/encodings/mod.rs
@@ -43,4 +43,3 @@ pub fn get_encoder(name: &str) -> Result<Box<dyn
QuantumEncoder>> {
)),
}
}
-
diff --git a/qdp/qdp-core/src/gpu/memory.rs b/qdp/qdp-core/src/gpu/memory.rs
index e822b183f..be2fe41d0 100644
--- a/qdp/qdp-core/src/gpu/memory.rs
+++ b/qdp/qdp-core/src/gpu/memory.rs
@@ -11,7 +11,7 @@ pub struct GpuBufferRaw {
impl GpuBufferRaw {
/// Get raw pointer to GPU memory
- ///
+ ///
/// # Safety
/// Valid only while GpuBufferRaw is alive
pub fn ptr(&self) -> *mut CuDoubleComplex {
@@ -20,7 +20,7 @@ impl GpuBufferRaw {
}
/// Quantum state vector on GPU
-///
+///
/// Manages complex128 array of size 2^n (n = qubits) in GPU memory.
/// Uses Arc for shared ownership (needed for DLPack/PyTorch integration).
/// Thread-safe: Send + Sync
@@ -40,7 +40,7 @@ impl GpuStateVector {
/// Allocates 2^n complex numbers on GPU (freed on drop)
pub fn new(_device: &Arc<CudaDevice>, qubits: usize) -> Result<Self> {
let _size_elements = 1 << qubits;
-
+
// Use alloc_zeros for device-side allocation (critical for
performance):
// - No CPU RAM usage (avoids OOM for large states)
// - No PCIe transfer (GPU hardware zero-fill)
@@ -51,9 +51,9 @@ impl GpuStateVector {
let zeros = vec![CuDoubleComplex { x: 0.0, y: 0.0 };
_size_elements];
let slice = _device.htod_sync_copy(&zeros)
.map_err(|e| MahoutError::MemoryAllocation(
- format!("Failed to allocate {} bytes of GPU memory
(qubits={}): {:?}",
- _size_elements *
std::mem::size_of::<CuDoubleComplex>(),
- qubits,
+ format!("Failed to allocate {} bytes of GPU memory
(qubits={}): {:?}",
+ _size_elements *
std::mem::size_of::<CuDoubleComplex>(),
+ qubits,
e)
))?;
@@ -63,7 +63,7 @@ impl GpuStateVector {
size_elements: _size_elements,
})
}
-
+
#[cfg(not(target_os = "linux"))]
{
// Non-Linux: compiles but GPU unavailable
@@ -72,7 +72,7 @@ impl GpuStateVector {
}
/// Get raw GPU pointer for DLPack/FFI
- ///
+ ///
/// # Safety
/// Valid while GpuStateVector or any Arc clone is alive
pub fn ptr(&self) -> *mut CuDoubleComplex {
diff --git a/qdp/qdp-core/src/gpu/mod.rs b/qdp/qdp-core/src/gpu/mod.rs
index 00e990ec2..23c020ea0 100644
--- a/qdp/qdp-core/src/gpu/mod.rs
+++ b/qdp/qdp-core/src/gpu/mod.rs
@@ -3,4 +3,3 @@ pub mod encodings;
pub use memory::GpuStateVector;
pub use encodings::{QuantumEncoder, AmplitudeEncoder, AngleEncoder,
BasisEncoder, get_encoder};
-
diff --git a/qdp/qdp-core/src/lib.rs b/qdp/qdp-core/src/lib.rs
index 99b9d5a0a..b8991c2de 100644
--- a/qdp/qdp-core/src/lib.rs
+++ b/qdp/qdp-core/src/lib.rs
@@ -10,7 +10,7 @@ use crate::dlpack::DLManagedTensor;
use crate::gpu::get_encoder;
/// Main entry point for Mahout QDP
-///
+///
/// Manages GPU context and dispatches encoding tasks.
/// Provides unified interface for device management, memory allocation, and
DLPack.
pub struct QdpEngine {
@@ -19,29 +19,29 @@ pub struct QdpEngine {
impl QdpEngine {
/// Initialize engine on GPU device
- ///
+ ///
/// # Arguments
/// * `device_id` - CUDA device ID (typically 0)
pub fn new(device_id: usize) -> Result<Self> {
let device = CudaDevice::new(device_id)
.map_err(|e| MahoutError::Cuda(format!("Failed to initialize CUDA
device {}: {:?}", device_id, e)))?;
- Ok(Self {
+ Ok(Self {
device // CudaDevice::new already returns Arc<CudaDevice> in
cudarc 0.11
})
}
/// Encode classical data into quantum state
- ///
+ ///
/// Selects encoding strategy, executes on GPU, returns DLPack pointer.
- ///
+ ///
/// # Arguments
/// * `data` - Input data
/// * `num_qubits` - Number of qubits
/// * `encoding_method` - Strategy: "amplitude", "angle", or "basis"
- ///
+ ///
/// # Returns
/// DLPack pointer for zero-copy PyTorch integration
- ///
+ ///
/// # Safety
/// Pointer freed by DLPack deleter, do not free manually.
pub fn encode(
diff --git a/qdp/qdp-kernels/build.rs b/qdp/qdp-kernels/build.rs
index a8b016bf6..007934a71 100644
--- a/qdp/qdp-kernels/build.rs
+++ b/qdp/qdp-kernels/build.rs
@@ -13,13 +13,13 @@ use std::process::Command;
fn main() {
// Tell Cargo to rerun this script if the kernel source changes
println!("cargo:rerun-if-changed=src/amplitude.cu");
-
+
// Check if CUDA is available by looking for nvcc
let has_cuda = Command::new("nvcc")
.arg("--version")
.output()
.is_ok();
-
+
if !has_cuda {
println!("cargo:warning=CUDA not found (nvcc not in PATH). Skipping
kernel compilation.");
println!("cargo:warning=This is expected on macOS or non-CUDA
environments.");
@@ -27,23 +27,23 @@ fn main() {
println!("cargo:warning=For production deployment, ensure CUDA toolkit
is installed.");
return;
}
-
+
// Get CUDA installation path
// Priority: CUDA_PATH env var > /usr/local/cuda (default Linux location)
let cuda_path = env::var("CUDA_PATH")
.unwrap_or_else(|_| "/usr/local/cuda".to_string());
-
+
println!("cargo:rustc-link-search=native={}/lib64", cuda_path);
println!("cargo:rustc-link-lib=cudart");
-
+
// On macOS, also check /usr/local/cuda/lib
#[cfg(target_os = "macos")]
println!("cargo:rustc-link-search=native={}/lib", cuda_path);
-
+
// Compile CUDA kernels
// This uses cc crate's CUDA support to invoke nvcc
let mut build = cc::Build::new();
-
+
build
.cuda(true)
.flag("-cudart=shared") // Use shared CUDA runtime
@@ -63,7 +63,6 @@ fn main() {
// .flag("arch=compute_89,code=sm_89")
.file("src/amplitude.cu")
.compile("kernels");
-
+
println!("cargo:warning=CUDA kernels compiled successfully");
}
-
diff --git a/qdp/qdp-kernels/src/amplitude.cu b/qdp/qdp-kernels/src/amplitude.cu
index f7bde4d9b..9e4537a71 100644
--- a/qdp/qdp-kernels/src/amplitude.cu
+++ b/qdp/qdp-kernels/src/amplitude.cu
@@ -17,7 +17,7 @@
extern "C" {
/// Launch amplitude encoding kernel (skeleton implementation)
-///
+///
/// TODO: Full implementation with:
/// - Parallel normalization kernel
/// - Coalesced memory access patterns
@@ -46,13 +46,13 @@ int launch_amplitude_encode(
) {
// Skeleton implementation - ensures FFI linkage is correct
// This allows the project to compile and pass CI/CD checks.
- //
+ //
// TODO: Implement full CUDA kernel:
// 1. Kernel launch with optimal grid/block dimensions
// 2. Parallel normalization and complex number construction
// 3. Zero-padding for unused state vector elements
// 4. Error checking and stream synchronization
-
+
// Suppress unused parameter warnings (parameters will be used in full
implementation)
(void)input_d;
(void)state_d;
@@ -60,7 +60,7 @@ int launch_amplitude_encode(
(void)state_len;
(void)norm;
(void)stream;
-
+
// For now, just return success
// TODO: Launch actual kernel here
return cudaSuccess;
@@ -72,4 +72,3 @@ int launch_amplitude_encode(
// - launch_iqp_encode (IQP encoding)
} // extern "C"
-
diff --git a/qdp/qdp-kernels/src/lib.rs b/qdp/qdp-kernels/src/lib.rs
index 8f1e4b5c2..2f7660f95 100644
--- a/qdp/qdp-kernels/src/lib.rs
+++ b/qdp/qdp-kernels/src/lib.rs
@@ -25,7 +25,7 @@ unsafe impl cudarc::driver::ValidAsZeroBits for
CuDoubleComplex {}
unsafe extern "C" {
/// Launch amplitude encoding kernel
/// Returns CUDA error code (0 = success)
- ///
+ ///
/// # Safety
/// Requires valid GPU pointers, must sync before freeing
pub fn launch_amplitude_encode(
@@ -53,4 +53,3 @@ pub extern "C" fn launch_amplitude_encode(
) -> i32 {
999 // Error: CUDA unavailable
}
-
diff --git a/qdp/qdp-python/.gitignore b/qdp/qdp-python/.gitignore
new file mode 100644
index 000000000..c8f044299
--- /dev/null
+++ b/qdp/qdp-python/.gitignore
@@ -0,0 +1,72 @@
+/target
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+.pytest_cache/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+.venv/
+env/
+bin/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+include/
+man/
+venv/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+pip-selfcheck.json
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# Rope
+.ropeproject
+
+# Django stuff:
+*.log
+*.pot
+
+.DS_Store
+
+# Sphinx documentation
+docs/_build/
+
+# PyCharm
+.idea/
+
+# VSCode
+.vscode/
+
+# Pyenv
+.python-version
diff --git a/qdp/qdp-python/Cargo.toml b/qdp/qdp-python/Cargo.toml
index ded35bfaa..b6fbbef7e 100644
--- a/qdp/qdp-python/Cargo.toml
+++ b/qdp/qdp-python/Cargo.toml
@@ -4,10 +4,9 @@ version.workspace = true
edition.workspace = true
[lib]
-name = "mahout"
+name = "mahout_qdp"
crate-type = ["cdylib"]
[dependencies]
-pyo3 = { version = "0.23", features = ["abi3-py311"] }
+pyo3 = { version = "0.27", features = ["extension-module"] }
qdp-core = { path = "../qdp-core" }
-cudarc = { workspace = true }
diff --git a/qdp/qdp-python/README.md b/qdp/qdp-python/README.md
new file mode 100644
index 000000000..f4d7b43b0
--- /dev/null
+++ b/qdp/qdp-python/README.md
@@ -0,0 +1,49 @@
+# qdp-python
+
+PyO3 Python bindings for Apache Mahout QDP.
+
+## Usage
+
+```python
+from mahout_qdp import QdpEngine
+
+# Initialize on GPU 0
+engine = QdpEngine(0)
+
+# Encode data
+data = [0.5, 0.5, 0.5, 0.5]
+dlpack_ptr = engine.encode(data, num_qubits=2, encoding_method="amplitude")
+```
+
+## Build from source
+
+```bash
+uv sync --extra dev
+uv run maturin develop
+```
+
+## Encoding methods
+
+- `"amplitude"` - Amplitude encoding
+- `"angle"` - Angle encoding
+- `"basis"` - Basis encoding
+
+## Adding new bindings
+
+1. Add method to `#[pymethods]` in `src/lib.rs`:
+```rust
+#[pymethods]
+impl QdpEngine {
+ fn my_method(&self, arg: f64) -> PyResult<String> {
+ Ok(format!("Result: {}", arg))
+ }
+}
+```
+
+2. Rebuild: `uv run maturin develop`
+
+3. Use in Python:
+```python
+engine = QdpEngine(0)
+result = engine.my_method(42.0)
+```
diff --git a/qdp/qdp-python/pyproject.toml b/qdp/qdp-python/pyproject.toml
new file mode 100644
index 000000000..b109b30fc
--- /dev/null
+++ b/qdp/qdp-python/pyproject.toml
@@ -0,0 +1,32 @@
+[build-system]
+requires = ["maturin>=1.10,<2.0"]
+build-backend = "maturin"
+
+[project]
+name = "qdp-python"
+requires-python = ">=3.11"
+classifiers = [
+ "Programming Language :: Rust",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
+]
+dynamic = ["version"]
+
+[dependency-groups]
+dev = [
+ "maturin>=1.10.2",
+ "patchelf>=0.17.2.4",
+ "pytest>=9.0.1",
+ "torch>=2.2,<2.3",
+]
+
+[[tool.uv.index]]
+name = "pytorch"
+url = "https://download.pytorch.org/whl/cu122"
+explicit = true
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]
+markers = [
+ "gpu: tests that require GPU (deselect with '-m \"not gpu\"')",
+]
diff --git a/qdp/qdp-python/src/lib.rs b/qdp/qdp-python/src/lib.rs
new file mode 100644
index 000000000..c5490b717
--- /dev/null
+++ b/qdp/qdp-python/src/lib.rs
@@ -0,0 +1,172 @@
+use pyo3::prelude::*;
+use pyo3::exceptions::PyRuntimeError;
+use pyo3::ffi;
+use qdp_core::QdpEngine as CoreEngine;
+use qdp_core::dlpack::DLManagedTensor;
+
+/// Quantum tensor wrapper implementing DLPack protocol
+///
+/// This class wraps a GPU-allocated quantum state vector and implements
+/// the DLPack protocol for zero-copy integration with PyTorch and other
+/// array libraries.
+///
+/// Example:
+/// >>> engine = QdpEngine(device_id=0)
+/// >>> qtensor = engine.encode([1.0, 2.0, 3.0], num_qubits=2,
encoding_method="amplitude")
+/// >>> torch_tensor = torch.from_dlpack(qtensor)
+#[pyclass]
+struct QuantumTensor {
+ ptr: *mut DLManagedTensor,
+ consumed: bool,
+}
+
+#[pymethods]
+impl QuantumTensor {
+ /// Implements DLPack protocol - returns PyCapsule for PyTorch
+ ///
+ /// This method is called by torch.from_dlpack() to get the GPU memory
pointer.
+ /// The capsule can only be consumed once to prevent double-free errors.
+ ///
+ /// Args:
+ /// stream: Optional CUDA stream pointer (for DLPack 0.8+)
+ ///
+ /// Returns:
+ /// PyCapsule containing DLManagedTensor pointer
+ ///
+ /// Raises:
+ /// RuntimeError: If the tensor has already been consumed
+ #[pyo3(signature = (stream=None))]
+ fn __dlpack__<'py>(&mut self, py: Python<'py>, stream: Option<i64>) ->
PyResult<Py<PyAny>> {
+ let _ = stream; // Suppress unused variable warning
+ if self.consumed {
+ return Err(PyRuntimeError::new_err(
+ "DLPack tensor already consumed (can only be used once)"
+ ));
+ }
+
+ if self.ptr.is_null() {
+ return Err(PyRuntimeError::new_err("Invalid DLPack tensor
pointer"));
+ }
+
+ // Mark as consumed to prevent double-free
+ self.consumed = true;
+
+ // Create PyCapsule using FFI
+ // PyTorch will call the deleter stored in DLManagedTensor.deleter
+ // Use a static C string for the capsule name to avoid lifetime issues
+ const DLTENSOR_NAME: &[u8] = b"dltensor\0";
+
+ unsafe {
+ // Create PyCapsule without a destructor
+ // PyTorch will manually call the deleter from DLManagedTensor
+ let capsule_ptr = ffi::PyCapsule_New(
+ self.ptr as *mut std::ffi::c_void,
+ DLTENSOR_NAME.as_ptr() as *const i8,
+ None // No destructor - PyTorch handles it
+ );
+
+ if capsule_ptr.is_null() {
+ return Err(PyRuntimeError::new_err("Failed to create
PyCapsule"));
+ }
+
+ Ok(Py::from_owned_ptr(py, capsule_ptr))
+ }
+ }
+
+ /// Returns DLPack device information
+ ///
+ /// Returns:
+ /// Tuple of (device_type, device_id) where device_type=2 for CUDA
+ fn __dlpack_device__(&self) -> PyResult<(i32, i32)> {
+ // DLDeviceType::kDLCUDA = 2, device_id = 0
+ Ok((2, 0))
+ }
+}
+
+impl Drop for QuantumTensor {
+ fn drop(&mut self) {
+ // Only free if not consumed by __dlpack__
+ // If consumed, PyTorch/consumer will call the deleter
+ if !self.consumed && !self.ptr.is_null() {
+ unsafe {
+ // Call the DLPack deleter to properly free memory
+ if let Some(deleter) = (*self.ptr).deleter {
+ deleter(self.ptr);
+ }
+ }
+ }
+ }
+}
+
+// Safety: QuantumTensor can be sent between threads
+// The DLManagedTensor pointer management is thread-safe via Arc in the deleter
+unsafe impl Send for QuantumTensor {}
+unsafe impl Sync for QuantumTensor {}
+
+/// PyO3 wrapper for QdpEngine
+///
+/// Provides Python bindings for GPU-accelerated quantum state encoding.
+#[pyclass]
+struct QdpEngine {
+ engine: CoreEngine,
+}
+
+#[pymethods]
+impl QdpEngine {
+ /// Initialize QDP engine on specified GPU device
+ ///
+ /// Args:
+ /// device_id: CUDA device ID (typically 0)
+ ///
+ /// Returns:
+ /// QdpEngine instance
+ ///
+ /// Raises:
+ /// RuntimeError: If CUDA device initialization fails
+ #[new]
+ #[pyo3(signature = (device_id=0))]
+ fn new(device_id: usize) -> PyResult<Self> {
+ let engine = CoreEngine::new(device_id)
+ .map_err(|e| PyRuntimeError::new_err(format!("Failed to
initialize: {}", e)))?;
+ Ok(Self { engine })
+ }
+
+ /// Encode classical data into quantum state
+ ///
+ /// Args:
+ /// data: Input data as list of floats
+ /// num_qubits: Number of qubits for encoding
+ /// encoding_method: Encoding strategy ("amplitude", "angle", or
"basis")
+ ///
+ /// Returns:
+ /// QuantumTensor: DLPack-compatible tensor for zero-copy PyTorch
integration
+ ///
+ /// Raises:
+ /// RuntimeError: If encoding fails
+ ///
+ /// Example:
+ /// >>> engine = QdpEngine(device_id=0)
+ /// >>> qtensor = engine.encode([1.0, 2.0, 3.0, 4.0], num_qubits=2,
encoding_method="amplitude")
+ /// >>> torch_tensor = torch.from_dlpack(qtensor)
+ ///
+ /// TODO: Replace Vec<f64> with numpy array input to enable zero-copy
reading.
+ /// Consider using the numpy crate (e.g., PyReadonlyArray1<f64>) for
better performance.
+ fn encode(&self, data: Vec<f64>, num_qubits: usize, encoding_method: &str)
-> PyResult<QuantumTensor> {
+ let ptr = self.engine.encode(&data, num_qubits, encoding_method)
+ .map_err(|e| PyRuntimeError::new_err(format!("Encoding failed:
{}", e)))?;
+ Ok(QuantumTensor {
+ ptr,
+ consumed: false,
+ })
+ }
+}
+
+/// Mahout QDP Python module
+///
+/// GPU-accelerated quantum data encoding with DLPack integration.
+#[pymodule]
+fn mahout_qdp(m: &Bound<'_, PyModule>) -> PyResult<()> {
+ m.add_class::<QdpEngine>()?;
+ m.add_class::<QuantumTensor>()?;
+ Ok(())
+}
diff --git a/qdp/qdp-python/tests/test_bindings.py
b/qdp/qdp-python/tests/test_bindings.py
new file mode 100644
index 000000000..0f7866299
--- /dev/null
+++ b/qdp/qdp-python/tests/test_bindings.py
@@ -0,0 +1,91 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Simple tests for PyO3 bindings."""
+
+import pytest
+import mahout_qdp
+
+
+def test_import():
+ """Test that PyO3 bindings are properly imported."""
+ assert hasattr(mahout_qdp, "QdpEngine")
+ assert hasattr(mahout_qdp, "QuantumTensor")
+
+
[email protected]
+def test_encode():
+ """Test encoding returns QuantumTensor (requires GPU)."""
+ from mahout_qdp import QdpEngine
+
+ engine = QdpEngine(0)
+ data = [0.5, 0.5, 0.5, 0.5]
+ qtensor = engine.encode(data, 2, "amplitude")
+ assert isinstance(qtensor, mahout_qdp.QuantumTensor)
+
+
[email protected]
+def test_dlpack_device():
+ """Test __dlpack_device__ method (requires GPU)."""
+ from mahout_qdp import QdpEngine
+
+ engine = QdpEngine(0)
+ data = [1.0, 2.0, 3.0, 4.0]
+ qtensor = engine.encode(data, 2, "amplitude")
+
+ device_info = qtensor.__dlpack_device__()
+ assert device_info == (2, 0), "Expected (2, 0) for CUDA device 0"
+
+
[email protected]
+def test_dlpack_single_use():
+ """Test that __dlpack__ can only be called once (requires GPU)."""
+ import torch
+ from mahout_qdp import QdpEngine
+
+ engine = QdpEngine(0)
+ data = [1.0, 2.0, 3.0, 4.0]
+ qtensor = engine.encode(data, 2, "amplitude")
+
+ # First call succeeds - let PyTorch consume it
+ _ = torch.from_dlpack(qtensor)
+
+ # Second call should fail because tensor was already consumed
+ qtensor2 = engine.encode(data, 2, "amplitude")
+ _ = qtensor2.__dlpack__() # Consume the capsule
+ with pytest.raises(RuntimeError, match="already consumed"):
+ qtensor2.__dlpack__()
+
+
[email protected]
+def test_pytorch_integration():
+ """Test PyTorch integration via DLPack (requires GPU and PyTorch)."""
+ pytest.importorskip("torch")
+ import torch
+ from mahout_qdp import QdpEngine
+
+ engine = QdpEngine(0)
+ data = [1.0, 2.0, 3.0, 4.0]
+ qtensor = engine.encode(data, 2, "amplitude")
+
+ # Convert to PyTorch tensor using DLPack
+ torch_tensor = torch.from_dlpack(qtensor)
+ assert torch_tensor.is_cuda
+ assert torch_tensor.device.index == 0
+ assert torch_tensor.dtype == torch.complex128
+
+ # Verify shape (2 qubits = 2^2 = 4 elements)
+ assert torch_tensor.shape == (4,)
diff --git a/qdp/qdp-python/uv.lock b/qdp/qdp-python/uv.lock
new file mode 100644
index 000000000..07b338f5e
--- /dev/null
+++ b/qdp/qdp-python/uv.lock
@@ -0,0 +1,422 @@
+version = 1
+revision = 3
+requires-python = ">=3.11"
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz",
hash =
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size
= 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
hash =
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size
= 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "filelock"
+version = "3.20.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz",
hash =
"sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size
= 18922, upload-time = "2025-10-08T18:03:50.056Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl",
hash =
"sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size
= 16054, upload-time = "2025-10-08T18:03:48.35Z" },
+]
+
+[[package]]
+name = "fsspec"
+version = "2025.10.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz",
hash =
"sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size
= 309285, upload-time = "2025-10-30T14:58:44.036Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl",
hash =
"sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size
= 200966, upload-time = "2025-10-30T14:58:42.53Z" },
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz",
hash =
"sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size
= 20503, upload-time = "2025-10-18T21:55:43.219Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl",
hash =
"sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size
= 7484, upload-time = "2025-10-18T21:55:41.639Z" },
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "markupsafe" },
+]
+sdist = { url =
"https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz",
hash =
"sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size
= 245115, upload-time = "2025-03-05T20:05:02.478Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl",
hash =
"sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size
= 134899, upload-time = "2025-03-05T20:05:00.369Z" },
+]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz",
hash =
"sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size
= 80313, upload-time = "2025-09-27T18:37:40.426Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl",
hash =
"sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size
= 11631, upload-time = "2025-09-27T18:36:18.185Z" },
+ { url =
"https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl",
hash =
"sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size
= 12058, upload-time = "2025-09-27T18:36:19.444Z" },
+ { url =
"https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size
= 24287, upload-time = "2025-09-27T18:36:20.768Z" },
+ { url =
"https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size
= 22940, upload-time = "2025-09-27T18:36:22.249Z" },
+ { url =
"https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size
= 21887, upload-time = "2025-09-27T18:36:23.535Z" },
+ { url =
"https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl",
hash =
"sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size
= 23692, upload-time = "2025-09-27T18:36:24.823Z" },
+ { url =
"https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl",
hash =
"sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size
= 21471, upload-time = "2025-09-27T18:36:25.95Z" },
+ { url =
"https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl",
hash =
"sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size
= 22923, upload-time = "2025-09-27T18:36:27.109Z" },
+ { url =
"https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl",
hash =
"sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size
= 14572, upload-time = "2025-09-27T18:36:28.045Z" },
+ { url =
"https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl",
hash =
"sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size
= 15077, upload-time = "2025-09-27T18:36:29.025Z" },
+ { url =
"https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl",
hash =
"sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size
= 13876, upload-time = "2025-09-27T18:36:29.954Z" },
+ { url =
"https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl",
hash =
"sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size
= 11615, upload-time = "2025-09-27T18:36:30.854Z" },
+ { url =
"https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl",
hash =
"sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size
= 12020, upload-time = "2025-09-27T18:36:31.971Z" },
+ { url =
"https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size
= 24332, upload-time = "2025-09-27T18:36:32.813Z" },
+ { url =
"https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size
= 22947, upload-time = "2025-09-27T18:36:33.86Z" },
+ { url =
"https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size
= 21962, upload-time = "2025-09-27T18:36:35.099Z" },
+ { url =
"https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl",
hash =
"sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size
= 23760, upload-time = "2025-09-27T18:36:36.001Z" },
+ { url =
"https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl",
hash =
"sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size
= 21529, upload-time = "2025-09-27T18:36:36.906Z" },
+ { url =
"https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl",
hash =
"sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size
= 23015, upload-time = "2025-09-27T18:36:37.868Z" },
+ { url =
"https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl",
hash =
"sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size
= 14540, upload-time = "2025-09-27T18:36:38.761Z" },
+ { url =
"https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl",
hash =
"sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size
= 15105, upload-time = "2025-09-27T18:36:39.701Z" },
+ { url =
"https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl",
hash =
"sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size
= 13906, upload-time = "2025-09-27T18:36:40.689Z" },
+ { url =
"https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl",
hash =
"sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size
= 11622, upload-time = "2025-09-27T18:36:41.777Z" },
+ { url =
"https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl",
hash =
"sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size
= 12029, upload-time = "2025-09-27T18:36:43.257Z" },
+ { url =
"https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size
= 24374, upload-time = "2025-09-27T18:36:44.508Z" },
+ { url =
"https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size
= 22980, upload-time = "2025-09-27T18:36:45.385Z" },
+ { url =
"https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size
= 21990, upload-time = "2025-09-27T18:36:46.916Z" },
+ { url =
"https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl",
hash =
"sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size
= 23784, upload-time = "2025-09-27T18:36:47.884Z" },
+ { url =
"https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl",
hash =
"sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size
= 21588, upload-time = "2025-09-27T18:36:48.82Z" },
+ { url =
"https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl",
hash =
"sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size
= 23041, upload-time = "2025-09-27T18:36:49.797Z" },
+ { url =
"https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl",
hash =
"sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size
= 14543, upload-time = "2025-09-27T18:36:51.584Z" },
+ { url =
"https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl",
hash =
"sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size
= 15113, upload-time = "2025-09-27T18:36:52.537Z" },
+ { url =
"https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl",
hash =
"sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size
= 13911, upload-time = "2025-09-27T18:36:53.513Z" },
+ { url =
"https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl",
hash =
"sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size
= 11658, upload-time = "2025-09-27T18:36:54.819Z" },
+ { url =
"https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl",
hash =
"sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size
= 12066, upload-time = "2025-09-27T18:36:55.714Z" },
+ { url =
"https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size
= 25639, upload-time = "2025-09-27T18:36:56.908Z" },
+ { url =
"https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size
= 23569, upload-time = "2025-09-27T18:36:57.913Z" },
+ { url =
"https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size
= 23284, upload-time = "2025-09-27T18:36:58.833Z" },
+ { url =
"https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl",
hash =
"sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size
= 24801, upload-time = "2025-09-27T18:36:59.739Z" },
+ { url =
"https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl",
hash =
"sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size
= 22769, upload-time = "2025-09-27T18:37:00.719Z" },
+ { url =
"https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl",
hash =
"sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size
= 23642, upload-time = "2025-09-27T18:37:01.673Z" },
+ { url =
"https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl",
hash =
"sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size
= 14612, upload-time = "2025-09-27T18:37:02.639Z" },
+ { url =
"https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl",
hash =
"sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size
= 15200, upload-time = "2025-09-27T18:37:03.582Z" },
+ { url =
"https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl",
hash =
"sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size
= 13973, upload-time = "2025-09-27T18:37:04.929Z" },
+ { url =
"https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl",
hash =
"sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size
= 11619, upload-time = "2025-09-27T18:37:06.342Z" },
+ { url =
"https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl",
hash =
"sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size
= 12029, upload-time = "2025-09-27T18:37:07.213Z" },
+ { url =
"https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size
= 24408, upload-time = "2025-09-27T18:37:09.572Z" },
+ { url =
"https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size
= 23005, upload-time = "2025-09-27T18:37:10.58Z" },
+ { url =
"https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size
= 22048, upload-time = "2025-09-27T18:37:11.547Z" },
+ { url =
"https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl",
hash =
"sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size
= 23821, upload-time = "2025-09-27T18:37:12.48Z" },
+ { url =
"https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl",
hash =
"sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size
= 21606, upload-time = "2025-09-27T18:37:13.485Z" },
+ { url =
"https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl",
hash =
"sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size
= 23043, upload-time = "2025-09-27T18:37:14.408Z" },
+ { url =
"https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl",
hash =
"sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size
= 14747, upload-time = "2025-09-27T18:37:15.36Z" },
+ { url =
"https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl",
hash =
"sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size
= 15341, upload-time = "2025-09-27T18:37:16.496Z" },
+ { url =
"https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl",
hash =
"sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size
= 14073, upload-time = "2025-09-27T18:37:17.476Z" },
+ { url =
"https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl",
hash =
"sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size
= 11661, upload-time = "2025-09-27T18:37:18.453Z" },
+ { url =
"https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl",
hash =
"sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size
= 12069, upload-time = "2025-09-27T18:37:19.332Z" },
+ { url =
"https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl",
hash =
"sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size
= 25670, upload-time = "2025-09-27T18:37:20.245Z" },
+ { url =
"https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
hash =
"sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size
= 23598, upload-time = "2025-09-27T18:37:21.177Z" },
+ { url =
"https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl",
hash =
"sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size
= 23261, upload-time = "2025-09-27T18:37:22.167Z" },
+ { url =
"https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl",
hash =
"sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size
= 24835, upload-time = "2025-09-27T18:37:23.296Z" },
+ { url =
"https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl",
hash =
"sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size
= 22733, upload-time = "2025-09-27T18:37:24.237Z" },
+ { url =
"https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl",
hash =
"sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size
= 23672, upload-time = "2025-09-27T18:37:25.271Z" },
+ { url =
"https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl",
hash =
"sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size
= 14819, upload-time = "2025-09-27T18:37:26.285Z" },
+ { url =
"https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl",
hash =
"sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size
= 15426, upload-time = "2025-09-27T18:37:27.316Z" },
+ { url =
"https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl",
hash =
"sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size
= 14146, upload-time = "2025-09-27T18:37:28.327Z" },
+]
+
+[[package]]
+name = "maturin"
+version = "1.10.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/02/44/c593afce7d418ae6016b955c978055232359ad28c707a9ac6643fc60512d/maturin-1.10.2.tar.gz",
hash =
"sha256:259292563da89850bf8f7d37aa4ddba22905214c1e180b1c8f55505dfd8c0e81", size
= 217835, upload-time = "2025-11-19T11:53:17.348Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/15/74/7f7e93019bb71aa072a7cdf951cbe4c9a8d5870dd86c66ec67002153487f/maturin-1.10.2-py3-none-linux_armv6l.whl",
hash =
"sha256:11c73815f21a755d2129c410e6cb19dbfacbc0155bfc46c706b69930c2eb794b", size
= 8763201, upload-time = "2025-11-19T11:52:42.98Z" },
+ { url =
"https://files.pythonhosted.org/packages/4a/85/1d1b64dbb6518ee633bfde8787e251ae59428818fea7a6bdacb8008a09bd/maturin-1.10.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl",
hash =
"sha256:7fbd997c5347649ee7987bd05a92bd5b8b07efa4ac3f8bcbf6196e07eb573d89", size
= 17072583, upload-time = "2025-11-19T11:52:45.636Z" },
+ { url =
"https://files.pythonhosted.org/packages/7c/45/2418f0d6e1cbdf890205d1dc73ebea6778bb9ce80f92e866576c701ded72/maturin-1.10.2-py3-none-macosx_10_12_x86_64.whl",
hash =
"sha256:e3ce9b2ad4fb9c341f450a6d32dc3edb409a2d582a81bc46ba55f6e3b6196b22", size
= 8827021, upload-time = "2025-11-19T11:52:48.143Z" },
+ { url =
"https://files.pythonhosted.org/packages/7f/83/14c96ddc93b38745d8c3b85126f7d78a94f809a49dc9644bb22b0dc7b78c/maturin-1.10.2-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl",
hash =
"sha256:f0d1b7b5f73c8d30a7e71cd2a2189a7f0126a3a3cd8b3d6843e7e1d4db50f759", size
= 8751780, upload-time = "2025-11-19T11:52:51.613Z" },
+ { url =
"https://files.pythonhosted.org/packages/46/8d/753148c0d0472acd31a297f6d11c3263cd2668d38278ed29d523625f7290/maturin-1.10.2-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl",
hash =
"sha256:efcd496a3202ffe0d0489df1f83d08b91399782fb2dd545d5a1e7bf6fd81af39", size
= 9241884, upload-time = "2025-11-19T11:52:53.946Z" },
+ { url =
"https://files.pythonhosted.org/packages/b9/f9/f5ca9fe8cad70cac6f3b6008598cc708f8a74dd619baced99784a6253f23/maturin-1.10.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl",
hash =
"sha256:a41ec70d99e27c05377be90f8e3c3def2a7bae4d0d9d5ea874aaf2d1da625d5c", size
= 8671736, upload-time = "2025-11-19T11:52:57.133Z" },
+ { url =
"https://files.pythonhosted.org/packages/0a/76/f59cbcfcabef0259c3971f8b5754c85276a272028d8363386b03ec4e9947/maturin-1.10.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl",
hash =
"sha256:07a82864352feeaf2167247c8206937ef6c6ae9533025d416b7004ade0ea601d", size
= 8633475, upload-time = "2025-11-19T11:53:00.389Z" },
+ { url =
"https://files.pythonhosted.org/packages/53/40/96cd959ad1dda6c12301860a74afece200a3209d84b393beedd5d7d915c0/maturin-1.10.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl",
hash =
"sha256:04df81ee295dcda37828bd025a4ac688ea856e3946e4cb300a8f44a448de0069", size
= 11177118, upload-time = "2025-11-19T11:53:03.014Z" },
+ { url =
"https://files.pythonhosted.org/packages/e5/b6/144f180f36314be183f5237011528f0e39fe5fd2e74e65c3b44a5795971e/maturin-1.10.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:96e1d391e4c1fa87edf2a37e4d53d5f2e5f39dd880b9d8306ac9f8eb212d23f8", size
= 9320218, upload-time = "2025-11-19T11:53:05.39Z" },
+ { url =
"https://files.pythonhosted.org/packages/eb/2d/2c483c1b3118e2e10fd8219d5291843f5f7c12284113251bf506144a3ac1/maturin-1.10.2-py3-none-manylinux_2_31_riscv64.whl",
hash =
"sha256:a217aa7c42aa332fb8e8377eb07314e1f02cf0fe036f614aca4575121952addd", size
= 8985266, upload-time = "2025-11-19T11:53:07.618Z" },
+ { url =
"https://files.pythonhosted.org/packages/1d/98/1d0222521e112cd058b56e8d96c72cf9615f799e3b557adb4b16004f42aa/maturin-1.10.2-py3-none-win32.whl",
hash =
"sha256:da031771d9fb6ddb1d373638ec2556feee29e4507365cd5749a2d354bcadd818", size
= 7667897, upload-time = "2025-11-19T11:53:10.14Z" },
+ { url =
"https://files.pythonhosted.org/packages/a0/ec/c6c973b1def0d04533620b439d5d7aebb257657ba66710885394514c8045/maturin-1.10.2-py3-none-win_amd64.whl",
hash =
"sha256:da777766fd584440dc9fecd30059a94f85e4983f58b09e438ae38ee4b494024c", size
= 8908416, upload-time = "2025-11-19T11:53:12.862Z" },
+ { url =
"https://files.pythonhosted.org/packages/1b/01/7da60c9f7d5dc92dfa5e8888239fd0fb2613ee19e44e6db5c2ed5595fab3/maturin-1.10.2-py3-none-win_arm64.whl",
hash =
"sha256:a4c29a770ea2c76082e0afc6d4efd8ee94405588bfae00d10828f72e206c739b", size
= 7506680, upload-time = "2025-11-19T11:53:15.403Z" },
+]
+
+[[package]]
+name = "mpmath"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz",
hash =
"sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size
= 508106, upload-time = "2023-03-07T16:47:11.061Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl",
hash =
"sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size
= 536198, upload-time = "2023-03-07T16:47:09.197Z" },
+]
+
+[[package]]
+name = "networkx"
+version = "3.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/e8/fc/7b6fd4d22c8c4dc5704430140d8b3f520531d4fe7328b8f8d03f5a7950e8/networkx-3.6.tar.gz",
hash =
"sha256:285276002ad1f7f7da0f7b42f004bcba70d381e936559166363707fdad3d72ad", size
= 2511464, upload-time = "2025-11-24T03:03:47.158Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/07/c7/d64168da60332c17d24c0d2f08bdf3987e8d1ae9d84b5bbd0eec2eb26a55/networkx-3.6-py3-none-any.whl",
hash =
"sha256:cdb395b105806062473d3be36458d8f1459a4e4b98e236a66c3a48996e07684f", size
= 2063713, upload-time = "2025-11-24T03:03:45.21Z" },
+]
+
+[[package]]
+name = "nvidia-cublas-cu12"
+version = "12.1.3.1"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/37/6d/121efd7382d5b0284239f4ab1fc1590d86d34ed4a4a2fdb13b30ca8e5740/nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728", size
= 410594774, upload-time = "2023-04-19T15:50:03.519Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-cupti-cu12"
+version = "12.1.105"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/7e/00/6b218edd739ecfc60524e585ba8e6b00554dd908de2c9c66c1af3e44e18d/nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e", size
= 14109015, upload-time = "2023-04-19T15:47:32.502Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-nvrtc-cu12"
+version = "12.1.105"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/b6/9f/c64c03f49d6fbc56196664d05dba14e3a561038a81a638eeb47f4d4cfd48/nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2", size
= 23671734, upload-time = "2023-04-19T15:48:32.42Z" },
+]
+
+[[package]]
+name = "nvidia-cuda-runtime-cu12"
+version = "12.1.105"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/eb/d5/c68b1d2cdfcc59e72e8a5949a37ddb22ae6cade80cd4a57a84d4c8b55472/nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40", size
= 823596, upload-time = "2023-04-19T15:47:22.471Z" },
+]
+
+[[package]]
+name = "nvidia-cudnn-cu12"
+version = "8.9.2.26"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12" },
+]
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/ff/74/a2e2be7fb83aaedec84f391f082cf765dfb635e7caa9b49065f73e4835d8/nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9", size
= 731725872, upload-time = "2023-06-01T19:24:57.328Z" },
+]
+
+[[package]]
+name = "nvidia-cufft-cu12"
+version = "11.0.2.54"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/86/94/eb540db023ce1d162e7bea9f8f5aa781d57c65aed513c33ee9a5123ead4d/nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56", size
= 121635161, upload-time = "2023-04-19T15:50:46Z" },
+]
+
+[[package]]
+name = "nvidia-curand-cu12"
+version = "10.3.2.106"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/44/31/4890b1c9abc496303412947fc7dcea3d14861720642b49e8ceed89636705/nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0", size
= 56467784, upload-time = "2023-04-19T15:51:04.804Z" },
+]
+
+[[package]]
+name = "nvidia-cusolver-cu12"
+version = "11.4.5.107"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-cublas-cu12" },
+ { name = "nvidia-cusparse-cu12" },
+ { name = "nvidia-nvjitlink-cu12" },
+]
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd", size
= 124161928, upload-time = "2023-04-19T15:51:25.781Z" },
+]
+
+[[package]]
+name = "nvidia-cusparse-cu12"
+version = "12.1.0.106"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "nvidia-nvjitlink-cu12" },
+]
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c", size
= 195958278, upload-time = "2023-04-19T15:51:49.939Z" },
+]
+
+[[package]]
+name = "nvidia-nccl-cu12"
+version = "2.19.3"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/38/00/d0d4e48aef772ad5aebcf70b73028f88db6e5640b36c38e90445b7a57c45/nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d", size
= 165987969, upload-time = "2023-10-24T16:16:24.789Z" },
+]
+
+[[package]]
+name = "nvidia-nvjitlink-cu12"
+version = "12.9.86"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/46/0c/c75bbfb967457a0b7670b8ad267bfc4fffdf341c074e0a80db06c24ccfd4/nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl",
hash =
"sha256:e3f1171dbdc83c5932a45f0f4c99180a70de9bd2718c1ab77d14104f6d7147f9", size
= 39748338, upload-time = "2025-06-05T20:10:25.613Z" },
+]
+
+[[package]]
+name = "nvidia-nvtx-cu12"
+version = "12.1.105"
+source = { registry = "https://pypi.org/simple" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/da/d3/8057f0587683ed2fcd4dbfbdfdfa807b9160b809976099d36b8f60d08f03/nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl",
hash =
"sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5", size
= 99138, upload-time = "2023-04-19T15:48:43.556Z" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz",
hash =
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size
= 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl",
hash =
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size
= 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "patchelf"
+version = "0.17.2.4"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/2c/a3/fdd3fa938c864aa2f11dd0b7f08befeda983d2dcdee44da493c6977a653f/patchelf-0.17.2.4.tar.gz",
hash =
"sha256:970ee5cd8af33e5ea2099510b2f9013fa1b8d5cd763bf3fd3961281c18101a09", size
= 149629, upload-time = "2025-07-23T21:16:32.071Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/b1/a7/8c4f86c78ec03db954d05fd9c57a114cc3a172a2d3e4a8b949cd5ff89471/patchelf-0.17.2.4-py3-none-macosx_10_9_universal2.whl",
hash =
"sha256:343bb1b94e959f9070ca9607453b04390e36bbaa33c88640b989cefad0aa049e", size
= 184436, upload-time = "2025-07-23T21:16:20.578Z" },
+ { url =
"https://files.pythonhosted.org/packages/0b/6d/2e9f5483cdb352fab36b8076667b062b2d79cb09d2e3fd09b6fca5771cb6/patchelf-0.17.2.4-py3-none-manylinux1_i686.manylinux_2_5_i686.musllinux_1_1_i686.whl",
hash =
"sha256:09fd848d625a165fc7b7e07745508c24077129b019c4415a882938781d43adf8", size
= 547318, upload-time = "2025-07-23T21:16:22.135Z" },
+ { url =
"https://files.pythonhosted.org/packages/7e/19/f7821ef31aab01fa7dc8ebe697ece88ec4f7a0fdd3155dab2dfee4b00e5c/patchelf-0.17.2.4-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.musllinux_1_1_x86_64.whl",
hash =
"sha256:d9b35ebfada70c02679ad036407d9724ffe1255122ba4ac5e4be5868618a5689", size
= 482846, upload-time = "2025-07-23T21:16:23.73Z" },
+ { url =
"https://files.pythonhosted.org/packages/d1/50/107fea848ecfd851d473b079cab79107487d72c4c3cdb25b9d2603a24ca2/patchelf-0.17.2.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.musllinux_1_1_aarch64.whl",
hash =
"sha256:2931a1b5b85f3549661898af7bf746afbda7903c7c9a967cfc998a3563f84fad", size
= 477811, upload-time = "2025-07-23T21:16:25.145Z" },
+ { url =
"https://files.pythonhosted.org/packages/89/a9/a9a2103e159fd65bffbc21ecc5c8c36e44eb34fe53b4ef85fb6d08c2a635/patchelf-0.17.2.4-py3-none-manylinux2014_armv7l.manylinux_2_17_armv7l.musllinux_1_1_armv7l.whl",
hash =
"sha256:ae44cb3c857d50f54b99e5697aa978726ada33a8a6129d4b8b7ffd28b996652d", size
= 431226, upload-time = "2025-07-23T21:16:26.765Z" },
+ { url =
"https://files.pythonhosted.org/packages/87/93/897d612f6df7cfd987bdf668425127efeff8d8e4ad8bfbab1c69d2a0d861/patchelf-0.17.2.4-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.musllinux_1_1_ppc64le.whl",
hash =
"sha256:680a266a70f60a7a4f4c448482c5bdba80cc8e6bb155a49dcc24238ba49927b0", size
= 540276, upload-time = "2025-07-23T21:16:27.983Z" },
+ { url =
"https://files.pythonhosted.org/packages/5d/b8/2b92d11533482bac9ee989081d6880845287751b5f528adbd6bb27667fbd/patchelf-0.17.2.4-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.musllinux_1_1_s390x.whl",
hash =
"sha256:d842b51f0401460f3b1f3a3a67d2c266a8f515a5adfbfa6e7b656cb3ac2ed8bc", size
= 596632, upload-time = "2025-07-23T21:16:29.253Z" },
+ { url =
"https://files.pythonhosted.org/packages/14/e2/975d4bdb418f942b53e6187b95bd9e0d5e0488b7bc214685a1e43e2c2751/patchelf-0.17.2.4-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl",
hash =
"sha256:7076d9e127230982e20a81a6e2358d3343004667ba510d9f822d4fdee29b0d71", size
= 508281, upload-time = "2025-07-23T21:16:30.865Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz",
hash =
"sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size
= 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl",
hash =
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size
= 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz",
hash =
"sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size
= 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl",
hash =
"sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size
= 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "9.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "iniconfig" },
+ { name = "packaging" },
+ { name = "pluggy" },
+ { name = "pygments" },
+]
+sdist = { url =
"https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz",
hash =
"sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size
= 1564125, upload-time = "2025-11-12T13:05:09.333Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl",
hash =
"sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size
= 373668, upload-time = "2025-11-12T13:05:07.379Z" },
+]
+
+[[package]]
+name = "qdp-python"
+source = { editable = "." }
+
+[package.dev-dependencies]
+dev = [
+ { name = "maturin" },
+ { name = "patchelf" },
+ { name = "pytest" },
+ { name = "torch" },
+]
+
+[package.metadata]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "maturin", specifier = ">=1.10.2" },
+ { name = "patchelf", specifier = ">=0.17.2.4" },
+ { name = "pytest", specifier = ">=9.0.1" },
+ { name = "torch", specifier = ">=2.2,<2.3" },
+]
+
+[[package]]
+name = "sympy"
+version = "1.14.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mpmath" },
+]
+sdist = { url =
"https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz",
hash =
"sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size
= 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl",
hash =
"sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size
= 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
+]
+
+[[package]]
+name = "torch"
+version = "2.2.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+ { name = "fsspec" },
+ { name = "jinja2" },
+ { name = "networkx" },
+ { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64'
and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64'
and sys_platform == 'linux'" },
+ { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine ==
'x86_64' and sys_platform == 'linux'" },
+ { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64'
and sys_platform == 'linux'" },
+ { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64'
and sys_platform == 'linux'" },
+ { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and
sys_platform == 'linux'" },
+ { name = "sympy" },
+ { name = "triton", marker = "python_full_version < '3.12' and
platform_machine == 'x86_64' and sys_platform == 'linux'" },
+ { name = "typing-extensions" },
+]
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/c3/33/d7a6123231bd4d04c7005dde8507235772f3bc4622a25f3a88c016415d49/torch-2.2.2-cp311-cp311-manylinux1_x86_64.whl",
hash =
"sha256:ad4c03b786e074f46606f4151c0a1e3740268bcf29fbd2fdf6666d66341c1dcb", size
= 755555407, upload-time = "2024-03-27T21:09:48.166Z" },
+ { url =
"https://files.pythonhosted.org/packages/02/af/81abea3d73fddfde26afd1ce52a4ddfa389cd2b684c89d6c4d0d5d8d0dfa/torch-2.2.2-cp311-cp311-manylinux2014_aarch64.whl",
hash =
"sha256:32827fa1fbe5da8851686256b4cd94cc7b11be962862c2293811c94eea9457bf", size
= 86642063, upload-time = "2024-03-27T21:09:22.686Z" },
+ { url =
"https://files.pythonhosted.org/packages/5c/01/5ab75f138bf32d7a69df61e4997e24eccad87cc009f5fb7e2a31af8a4036/torch-2.2.2-cp311-cp311-win_amd64.whl",
hash =
"sha256:f9ef0a648310435511e76905f9b89612e45ef2c8b023bee294f5e6f7e73a3e7c", size
= 198584125, upload-time = "2024-03-27T21:10:06.958Z" },
+ { url =
"https://files.pythonhosted.org/packages/3f/14/e105b8ef6d324e789c1589e95cb0ab63f3e07c2216d68b1178b7c21b7d2a/torch-2.2.2-cp311-none-macosx_10_9_x86_64.whl",
hash =
"sha256:95b9b44f3bcebd8b6cd8d37ec802048c872d9c567ba52c894bba90863a439059", size
= 150796474, upload-time = "2024-03-27T21:09:29.142Z" },
+ { url =
"https://files.pythonhosted.org/packages/96/23/18b9c16c18a77755e7f15173821c7100f11e6b3b7717bea8d729bdeb92c0/torch-2.2.2-cp311-none-macosx_11_0_arm64.whl",
hash =
"sha256:49aa4126ede714c5aeef7ae92969b4b0bbe67f19665106463c39f22e0a1860d1", size
= 59714938, upload-time = "2024-03-27T21:09:34.709Z" },
+ { url =
"https://files.pythonhosted.org/packages/4c/0c/d8f77363a7a3350c96e6c9db4ffb101d1c0487cc0b8cdaae1e4bfb2800ad/torch-2.2.2-cp312-cp312-manylinux1_x86_64.whl",
hash =
"sha256:cf12cdb66c9c940227ad647bc9cf5dba7e8640772ae10dfe7569a0c1e2a28aca", size
= 755466713, upload-time = "2024-03-27T21:08:48.868Z" },
+ { url =
"https://files.pythonhosted.org/packages/05/9b/e5c0df26435f3d55b6699e1c61f07652b8c8a3ac5058a75d0e991f92c2b0/torch-2.2.2-cp312-cp312-manylinux2014_aarch64.whl",
hash =
"sha256:89ddac2a8c1fb6569b90890955de0c34e1724f87431cacff4c1979b5f769203c", size
= 86515814, upload-time = "2024-03-27T21:09:07.247Z" },
+ { url =
"https://files.pythonhosted.org/packages/72/ce/beca89dcdcf4323880d3b959ef457a4c61a95483af250e6892fec9174162/torch-2.2.2-cp312-cp312-win_amd64.whl",
hash =
"sha256:451331406b760f4b1ab298ddd536486ab3cfb1312614cfe0532133535be60bea", size
= 198528804, upload-time = "2024-03-27T21:09:14.691Z" },
+ { url =
"https://files.pythonhosted.org/packages/79/78/29dcab24a344ffd9ee9549ec0ab2c7885c13df61cde4c65836ee275efaeb/torch-2.2.2-cp312-none-macosx_10_9_x86_64.whl",
hash =
"sha256:eb4d6e9d3663e26cd27dc3ad266b34445a16b54908e74725adb241aa56987533", size
= 150797270, upload-time = "2024-03-27T21:08:29.623Z" },
+ { url =
"https://files.pythonhosted.org/packages/4a/0e/e4e033371a7cba9da0db5ccb507a9174e41b9c29189a932d01f2f61ecfc0/torch-2.2.2-cp312-none-macosx_11_0_arm64.whl",
hash =
"sha256:bf9558da7d2bf7463390b3b2a61a6a3dbb0b45b161ee1dd5ec640bf579d479fc", size
= 59678388, upload-time = "2024-03-27T21:08:35.869Z" },
+]
+
+[[package]]
+name = "triton"
+version = "2.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "filelock" },
+]
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/bd/ac/3974caaa459bf2c3a244a84be8d17561f631f7d42af370fc311defeca2fb/triton-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:da58a152bddb62cafa9a857dd2bc1f886dbf9f9c90a2b5da82157cd2b34392b0", size
= 167928356, upload-time = "2024-01-10T03:12:05.923Z" },
+ { url =
"https://files.pythonhosted.org/packages/0e/49/2e1bbae4542b8f624e409540b4197e37ab22a88e8685e99debe721cc2b50/triton-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:0af58716e721460a61886668b205963dc4d1e4ac20508cc3f623aef0d70283d5", size
= 167933985, upload-time = "2024-01-10T03:12:14.556Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz",
hash =
"sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size
= 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl",
hash =
"sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size
= 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]