Quantum
Quantum computing at CCI¶
CCI supports submitting jobs to the Quantum computer housed in the Voorhees Computing Center (VCC) through a Direct Access API (DA API) using Slurm.
Access to the quantum computer is available to all Rensselaer students and faculty.
Please note that quantum resource allocations are experimental and subject to change without notice.
Requesting Access¶
Access to quantum resources requires a CCI account and does not require IBM Cloud credentials.
- Request a CCI account: https://docs.cci.rpi.edu/accounts/CCI_projects/
Access requests generally take 1-2 business days to review.
Using Quantum Resources¶
Access to quantum resources is scheduled via Slurm. For more information on how to use Slurm, see this link.
Setup Environment
Create a new Conda environment
conda create -y --name <CONDA ENV NAME> python=3.12
conda activate <CONDA ENV NAME>
Install the Quantum Resource Management Interface Python wheel (QRMI)
QRMI is a vendor agnostic library to control state, run tasks and monitor behavior of quantum computational resources (qubits, QPUs, entire quantum systems, etc.)
QRMI acts like a thin middleware layer that abstracts away complexities of controling quantum resources by exposing set of simple APIs to acquire/release hardware, run tasks and monitor state of quantum resources.
More information and examples can be found here: https://github.com/qiskit-community/qrmi
pip install /gpfs/u/quantum/qrmi_wheelhouse/*.whl
This will install the QRMI wheel and pull in several required dependencies.
Create your submit file (Sbatch file)
NOTE: The "#" before the SBATCH directives are required and are NOT comments
submit.sh
#!/bin/bash
#quantum_submit.sh
#Example basic quantum sbatch submit script
#Slurm Directives
#SBATCH --mail-user=MY_RCSID@rpi.edu
#SBATCH --mail-type=end,fail
#SBATCH -N 1
#SBATCH --time=00:10:00
#SBATCH --gres=gpu:1
#SBATCH -p quantum
#SBATCH --qpu=ibm_rensselaer
# Clear the environment from any previously loaded modules
module purge > /dev/null 2>&1
# Load the modules required for your job
#DCS
module load gcc/15.1.0
module load cuda/12.1
#Activate Conda Environment
conda activate <CONDA ENV NAME>
#Optional debugging information
echo "Starting at `date`"
echo "Running on hosts: $SLURM_NODELIST"
echo "Running on $SLURM_NNODES nodes."
echo "Running $SLURM_NTASKS tasks."
echo "Current working directory is `pwd`"
#Run the script that does your work
python /gpfs/u/home/PROJ/PROJuser/barn/quantum_worker.sh
#Optional debugging information
echo "Program finished with exit code $? at: `date`"
Example quantum worker script
This example is to illustrate using QRMI to access the DA API.
The "Estimator" efficiently calculates and interprets expectation values of the quantum operators required for many algorithms.
quantum_worker.sh:
"""Estimator example using Direct Access QRMI"""
import random
from qiskit.circuit.library import QAOAAnsatz
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qrmi.primitives import QRMIService
from qrmi.primitives.ibm import EstimatorV2, get_target
# Create QRMI
service = QRMIService()
resources = service.resources()
if len(resources) == 0:
raise ValueError("No quantum resource is available.")
# Randomly select QR
qrmi = resources[random.randrange(len(resources))]
print(qrmi.metadata())
# Generate transpiler target from backend configuration & properties
target = get_target(qrmi)
# Create a circuit and an observable
# You need at least one circuit and one observable as inputs to the Estimator primitive.
entanglement = [tuple(edge) for edge in target.build_coupling_map().get_edges()]
observable = SparsePauliOp.from_sparse_list(
[("ZZ", [i, j], 0.5) for i, j in entanglement],
num_qubits=target.num_qubits,
)
circuit = QAOAAnsatz(observable, reps=2)
# the circuit is parametrized, so we will define the parameter values for execution
param_values = [0.1, 0.2, 0.3, 0.4]
print(f">>> Observable: {observable.paulis}")
# The circuit and observable need to be transformed to only use instructions
# supported by the QPU (referred to as instruction set architecture (ISA) circuits).
# We'll use the transpiler to do this.
pm = generate_preset_pass_manager(
optimization_level=1,
target=target,
)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
# Initialize QRMI Estimator
options = {}
estimator = EstimatorV2(qrmi, options=options)
# Invoke the Estimator and get results
# Next, invoke the run() method to calculate expectation values for the input circuits
# and observables. The circuit, observable, and optional parameter value sets are
# input as primitive unified bloc (PUB) tuples.
job = estimator.run([(isa_circuit, isa_observable, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
result = job.result()
print(f">>> {result}")
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
Submit your job
sbatch example_quantum.sh
You may check the status of your job using the squeue command.
Observe results
Once the job has started, a new file, slurm-
slurm-<12345678>.out:
Starting at Wed Oct 29 16:54:55 EDT 2025
Running on hosts: dcs264
Running on 1 nodes.
Running tasks.
Current working directory is /gpfs/u/home/CCNI/CCNIdmnn/barn/quantum_testing
{'backend_name': 'ibm_rensselaer'}
>>> Observable: ['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...', ...]
>>> Circuit ops (ISA): OrderedDict({'rz': 2727, 'sx': 1207, 'ecr': 576, 'x': 274})
>>> Job ID: 040588b6-d133-4599-b2bc-1cd1f32fda4d
>>> Job Status: JobStatus.RUNNING
>>> PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})
> Expectation value: 0.8428233559164482
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
Support¶
WRITE UP HOW TO GET SUPPORT HERE
TODO:
- ~~Test run (obv)~~
- ~~Explain how to run job subsequent to this crunching the results of quantum job~~
- Optimization
- Run from Jupyter notebook?
- Interactive sessions with salloc
- add resources section with info on RPI quantum clubs/groups
- add FAQs
- Add support section
- Does gres definition support multiple entries or does it require multiple lines
- Test multiple QPU definition/behaviour
- Document exclusivity, https://github.com/qiskit-community/spank-plugins/blob/main/docs/ux.md#hpc-user-scope-1
- ~~Explain how to get CRN/API key, if not duplicated with dotCIO docs~~
- How to run primitives direct, as in via a salloc allocation