Reusable Snakemake wrappers for running quantum tasks from HPC workflows, following the layout and conventions of the official snakemake-wrappers repository so that a quantum task becomes a normal rule in a workflow DAG.
Wrappers are organized by backend, as a domain tree like upstream snakemake-wrappers:
quantum/qrmi/— QRMI, the vendor-agnostic Quantum Resource Management Interface used with the Slurm SPANK plugin.quantum/braket/— Amazon Braket, AWS's managed quantum service.
New backends slot in as additional quantum/<backend>/ domains.
Each wrapper is a self-contained directory with a wrapper.py, an
environment.yaml, a meta.yaml, and a test/ case:
quantum/qrmi/
sampler/ run a Qiskit SamplerV2 primitive on a QRMI resource
estimator/ run a Qiskit EstimatorV2 primitive on a QRMI resource
task/ run one raw QRMI Qiskit-primitive task (vendor-agnostic, low-level)
quantum/braket/
authenticate/ verify AWS credentials / region (STS)
device_properties/ connect to a device and report its status
run/ run one circuit and wait for counts (submit + wait)
submit/ submit a circuit, return the durable task ARN (no wait)
poll/ recover a task by ARN and fetch its result
meta/quantum/
qrmi-sampler-summary/ meta-wrapper: QRMI sampler + classical summary
braket-run-summary/ meta-wrapper: Braket run + classical summary
workflows/ example workflows/apps that USE the wrappers in rules
test_wrappers.py pytest harness that runs each wrapper's testEach wrapper.py is self-contained: it uses the injected snakemake object and
calls the backend SDK (qrmi / qrmi.primitives, or braket) directly. There
is no shared helper package — copying a wrapper directory is enough to use it.
You need Python 3.11+ and Snakemake. You can use the provided VSCode Devcontainer, or create a fresh environment:
# with conda/mamba (recommended)
conda create -n quantum-wrappers -c conda-forge -c bioconda python=3.12 snakemake
conda activate quantum-wrappers
# or with pip
pip install snakemakeBackend SDKs are declared per wrapper in each environment.yaml. There are two
ways to get them:
- Let Snakemake manage them (recommended). Run with
--use-condaand Snakemake deploys each wrapper'senvironment.yamlinto an isolated conda env the first time it runs:
snakemake -c1 --use-conda- Install them yourself into the active environment, if you prefer not to use per-rule conda envs. For the offline path (local simulators, no QPU/AWS) that is just:
pip install qiskit qiskit-aer amazon-braket-sdk qiskit_qasm3_importAdd qrmi[ibm] / qiskit-ibm-runtime for real QRMI hardware, or configure AWS
credentials for real Braket devices.
To run the test suite (all offline):
pip install pytest
QRMI_WRAPPERS_SIMULATE=1 pytest -qA ready-made dev container (.devcontainer/devcontainer.json) is included: open
the repo in VS Code (or a Codespace) and "Reopen in Container" to get Python,
Snakemake, and the offline backend SDKs preinstalled.
| Wrapper | Unit of work | Input | Output |
|---|---|---|---|
quantum/qrmi/sampler |
Qiskit SamplerV2 on a QRMI resource |
OpenQASM 3 circuit(s) with measurements | per-circuit measurement counts |
quantum/qrmi/estimator |
Qiskit EstimatorV2 on a QRMI resource |
OpenQASM 3 state-prep circuit + Pauli observables | expectation values |
quantum/qrmi/task |
Raw QRMI lifecycle (acquire → task_start → poll → task_result → release) |
provider primitive input payload | raw result |
Each wrapper encapsulates the full acquire → run → release lifecycle in a
single process. That is deliberate: a QRMI lock is bound to the process that
acquired it, so the correct granularity for one Snakemake rule (which runs as its
own process) is one complete task — not a separate acquire rule and release
rule. The sampler/estimator wrappers build the Qiskit Runtime primitive input
for you; task submits a payload verbatim for any provider or program.
Here is locally:
rule sample:
input:
circuits="bell.qasm" # OpenQASM 3, with measurements
output:
"counts.json"
params:
resource="ibm_marrakesh", # or omit → first QRMI resource / Slurm SPANK
shots=2048
resources:
qpu=1 # serialise QPU access across the DAG
wrapper:
"file:../../quantum/qrmi/sampler"And reference to use from GitHub:
rule sample:
input:
circuits="bell.qasm"
output:
"counts.json"
params:
resource="ibm_marrakesh",
shots=2048
resources:
qpu=1
wrapper:
"github://converged-computing/quantum-wrappers/quantum/qrmi/sampler@main"For reproducibility you would normally pin a released version instead of a local
path, e.g. wrapper: "v0.1.0/quantum/qrmi/sampler" once this repo is tagged, and
run Snakemake with --use-conda so each wrapper's environment.yaml is deployed
automatically.
workflows/ contains runnable examples that use the wrappers in rules and
demonstrate common patterns:
| # | Workflow | Pattern |
|---|---|---|
| 01 | 01_single_circuit |
linear: sample one circuit → post-process |
| 02 | 02_parameter_sweep |
fan-out: sweep Ry(θ), one QPU task per angle, gather |
| 03 | 03_scatter_gather |
discover circuits/*.qasm, sample each, gather a batch |
| 04 | 04_vqe_estimator |
hybrid loop: an optimiser drives repeated EstimatorV2 evaluations while holding the resource |
Workflow 04 is intentionally a single rule running a driver rather than per-iteration wrapper rules: a hybrid loop must keep the resource acquired across all evaluations, so it uses the QRMI estimator API directly in one process.
Every wrapper's real path talks to a QRMI resource. For development and CI, set
QRMI_WRAPPERS_SIMULATE=1 to run the sampler/estimator paths (and the
example workflows) on a local Qiskit Aer / statevector simulator instead. This is
a test-only convenience; the default path is the real QRMI one, and the simulate
branch never imports qrmi.
# one wrapper's test
cd quantum/qrmi/sampler/test && QRMI_WRAPPERS_SIMULATE=1 snakemake -c1
# an example workflow
cd workflows/02_parameter_sweep && QRMI_WRAPPERS_SIMULATE=1 snakemake -c1
# the whole test suite
QRMI_WRAPPERS_SIMULATE=1 pytest -qThe task wrapper has no simulate path (it submits an opaque provider payload),
so its test runs only when a real resource is configured.
Untested - I (vsoch) do not have credentials still
Provide the resource and credentials via environment variables or a
qrmi_config.json, then run without QRMI_WRAPPERS_SIMULATE:
export QRMI_RESOURCE_ID=ibm_marrakesh
export QRMI_IBM_QS_IAM_APIKEY=... QRMI_IBM_QS_SERVICE_CRN=... QRMI_IBM_QS_ENDPOINT=...
snakemake -c1 --use-condaUnder Slurm with the QRMI SPANK plugin,
a job that requests a QPU (#SBATCH --qpu=<name>) has SLURM_JOB_QPU_RESOURCES
and the credential variables injected automatically; the wrappers pick the
resource up from there when params.resource is omitted, so the same workflow
runs unchanged as an sbatch script.
The Braket wrappers cover a finer separation of concerns — authenticate, connect / check the device, submit, poll, and a combined run:
| Wrapper | Unit of work | Offline (local sim)? |
|---|---|---|
quantum/braket/authenticate |
verify AWS credentials + region (STS GetCallerIdentity) |
no (needs AWS) |
quantum/braket/device_properties |
connect to a device, report name/status/provider/queue | yes |
quantum/braket/run |
run one OpenQASM 3 circuit and wait for counts (submit + wait) | yes |
quantum/braket/submit |
submit a circuit, return the durable task ARN, no wait | yes (local) |
quantum/braket/poll |
recover a task by ARN and fetch its result | no (needs AWS) |
All Braket wrappers take a device param that is either "local" /
"local:<backend>" (the in-process Braket simulator, no AWS account needed) or
an AWS device ARN such as
arn:aws:braket:::device/quantum-simulator/amazon/sv1 or a QPU ARN. Because the
local simulator is part of the real SDK, the run, submit, device_properties
and meta-wrapper tests run fully offline against genuine Braket code — no mock.
rule run:
input:
circuit="bell.qasm" # OpenQASM 3, Braket dialect, with measurements
output:
"counts.json"
params:
device="local:braket_sv", # or an AWS device ARN
shots=1000
wrapper:
"file:../../quantum/braket/run"The submit and poll wrappers are deliberately separate units, unlike the
single-process QRMI wrappers. A Braket quantum task is addressed by a durable
ARN, so submit can record the ARN and a later poll rule — in a different
process, Snakemake invocation, or Slurm job — can recover it with
AwsQuantumTask(arn=...) and fetch the result. That decoupling is not possible
with a QRMI lock, which is bound to the process that acquired it (hence the QRMI
sampler/estimator/task wrappers each own the full lifecycle in one rule).
The workflows/braket/submit_poll app demonstrates the two-rule pattern; it
requires an AWS device ARN, since a local task ARN does not survive its process.
Configure credentials the usual way (aws configure, environment variables, or
an instance/role), then point device at an AWS ARN:
export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION=us-east-1
cd workflows/braket/single_circuit
snakemake -c1 --config device=arn:aws:braket:::device/quantum-simulator/amazon/sv1Backends: QRMI (https://github.com/qiskit-community/qrmi) and Amazon Braket (https://github.com/amazon-braket/amazon-braket-sdk-python).
DevTools is distributed under the terms of the MIT license. All new contributions must be made under this license.
See LICENSE, COPYRIGHT, and NOTICE for details.
SPDX-License-Identifier: (MIT)
LLNL-CODE- 842614