On-demand access to Rigetti quantum systems (Ankaa, Cepheus) is restricted.
You must contact Rigetti to request access
credentials before using this provider.
Prerequisites
Before getting started, ensure you have:
- A Rigetti QCS account with an active refresh token (contact Rigetti to obtain access).
- The Forest SDK installed locally — specifically the
quilc compiler. The qvm simulator is optional.
- Python > 3.10 and < 3.13
Install the Forest SDK
The quilc compiler is required to compile Quil programs into the native gate set of the target QPU. Install it for your platform:
Verify the installation:
Installation & Setup
Install the rigetti extra:
pip install 'qbraid[rigetti]'
This installs the required dependencies: pyquil and qcs-sdk-python.
Authentication
The RigettiProvider authenticates with Rigetti QCS using an OAuth refresh token. Set it as an environment variable (required):
export RIGETTI_REFRESH_TOKEN="your-refresh-token"
Then initialize the provider:
from qbraid.runtime.rigetti import RigettiProvider
provider = RigettiProvider()
Optional Environment Variables
| Variable | Description | Default |
|---|
RIGETTI_CLIENT_ID | Custom OAuth client ID | Rigetti default |
RIGETTI_ISSUER | Custom OAuth issuer URL | Rigetti default |
QCS_GRPC_ENDPOINT | QCS gRPC API endpoint | https://grpc.qcs.rigetti.com |
QCS_QUILC_ENDPOINT | quilc compiler endpoint | tcp://127.0.0.1:5555 |
QCS_QVM_ENDPOINT | QVM simulator endpoint | http://127.0.0.1:5000 |
Provider Setup
After initializing the provider, call setup() to manage the local quilc compiler process. This ensures quilc is running and ready to compile programs:
provider = RigettiProvider()
# Start a local quilc process (default behavior)
provider.setup()
# Or, point to an existing quilc endpoint
provider.setup(quilc_endpoint="tcp://my-quilc-host:5555")
The setup() method accepts the following keyword arguments:
| Parameter | Type | Default | Description |
|---|
quilc_endpoint | str | None | Pre-existing quilc endpoint. Skips local process start. |
qvm_endpoint | str | None | Pre-existing QVM endpoint. Skips local process start. |
grpc_endpoint | str | None | Override for the QCS gRPC endpoint. |
start_quilc | bool | True | Auto-start local quilc if not already running. |
start_qvm | bool | False | Auto-start local QVM if not already running. |
Getting Available Devices
List all quantum processors available through your QCS account:
from qbraid.runtime.rigetti import RigettiProvider
provider = RigettiProvider()
provider.setup()
devices = provider.get_devices()
print(devices)
# [RigettiDevice('ankaa-3'), RigettiDevice('cepheus-108')]
Get a specific device by its processor ID:
device = provider.get_device("ankaa-3")
print(device.status())
# <DeviceStatus.ONLINE>
# Get the list of live qubit IDs on the device
qubits = device.live_qubits()
print(f"Live qubits ({len(qubits)}): {qubits[:10]}...")
Submitting Jobs
The RigettiProvider accepts programs written in Quil using the pyquil library. Programs are compiled via quilc before submission to the QPU.
Create a Program
from pyquil import Program
# Bell state circuit
program = Program("""
DECLARE ro BIT[2]
H 0
CNOT 0 1
MEASURE 0 ro[0]
MEASURE 1 ro[1]
""")
Run a Job
Use device.run() to compile and submit in one step:
from pyquil import Program
from qbraid.runtime.rigetti import RigettiProvider
provider = RigettiProvider()
provider.setup()
device = provider.get_device("ankaa-3")
program = Program("""
DECLARE ro BIT[2]
H 0
CNOT 0 1
MEASURE 0 ro[0]
MEASURE 1 ro[1]
""")
job = device.run(program, shots=1000)
print(f"Job ID: {job.id}")
Batch Submission
Submit multiple programs in a single call:
from pyquil import Program
from qbraid.runtime.rigetti import RigettiProvider
provider = RigettiProvider()
provider.setup()
device = provider.get_device("ankaa-3")
programs = [
Program("DECLARE ro BIT[1]\nH 0\nMEASURE 0 ro[0]"),
Program("DECLARE ro BIT[1]\nX 0\nMEASURE 0 ro[0]"),
Program("DECLARE ro BIT[1]\nH 0\nS 0\nMEASURE 0 ro[0]"),
]
jobs = device.run(programs, shots=500)
for job in jobs:
print(f"Job ID: {job.id}")
Retrieving Results
result = job.result()
# Measurement counts as a dictionary
print(result.data.measurement_counts)
# {'00': 512, '11': 488}
# Job metadata
print(f"Device: {result.device_id}")
print(f"Job ID: {result.job_id}")
print(f"Success: {result.success}")
print(f"Duration (us): {result.execution_duration_microseconds}")
Check Job Status
from qbraid.runtime.enums import JobStatus
status = job.status()
print(status)
# <JobStatus.COMPLETED>
Cancel a Job
Cancellation is best-effort. Jobs already in a terminal state (COMPLETED,
FAILED, CANCELLED) cannot be cancelled.
Runtime Options
The device.run() method accepts an optional runtime_options dict to control compilation
and translation behavior:
job = device.run(
program,
shots=1000,
runtime_options={
"compiler_timeout": 60,
"prepend_default_calibrations": True,
"passive_reset_delay_seconds": 1.0,
},
)
Options Reference
| Parameter | Type | Description |
|---|
compiler_timeout | float | quilc compilation timeout in seconds. |
prepend_default_calibrations | bool | Prepend default calibration pulses during translation. |
passive_reset_delay_seconds | float | Delay between passive resets. |
allow_unchecked_pointer_arithmetic | bool | Disable runtime memory bounds checking (authorized access). |
allow_frame_redefinition | bool | Allow frame definitions that differ from Rigetti defaults (authorized access). |
Full Example
A complete end-to-end workflow targeting the Ankaa-3 processor:
import os
from pyquil import Program
from qbraid.runtime.rigetti import RigettiProvider
# 1. Set credentials (or export as env var beforehand)
os.environ["RIGETTI_REFRESH_TOKEN"] = "your-refresh-token"
# 2. Initialize provider and start quilc
provider = RigettiProvider()
provider.setup()
# 3. Get the target device
device = provider.get_device("ankaa-3")
print(f"Device status: {device.status()}")
print(f"Number of qubits: {len(device.live_qubits())}")
# 4. Define a GHZ state circuit
program = Program("""
DECLARE ro BIT[3]
H 0
CNOT 0 1
CNOT 1 2
MEASURE 0 ro[0]
MEASURE 1 ro[1]
MEASURE 2 ro[2]
""")
# 5. Submit the job
job = device.run(program, shots=1000)
print(f"Submitted job: {job.id}")
# 6. Retrieve results
result = job.result()
print(f"Counts: {result.data.measurement_counts}")
# Expected output (approximate): {'000': ~500, '111': ~500}