Amazon Braket
The Strangeworks Platform supports Amazon Braket, a fully managed quantum computing service that helps you get started with quantum computing. Amazon Braket provides a development environment for you to explore and build quantum algorithms, test them on quantum circuit simulators, and run them on different quantum hardware technologies.
strangeworks-braketā
The strangeworks-braket
SDK provides a drop-in replacement for code written for Amazon Braket.
Installationā
To get started, make sure you have Python 3.10 or 3.11 (installation) and are familiar with setting up and using virtual environments.
pip install -U pip && pip install strangeworks-braket
Authenticationā
First, authenticate via the Strangeworks SDK with your api-key taken from the Portal homepage:
import strangeworks as sw
from strangeworks_braket import StrangeworksDevice
sw.authenticate(api_key="api-key")
Backendsā
devices = StrangeworksDevice.get_devices(statuses=["ONLINE"])
print("Available devices:")
for device in devices:
print(f" - {device.name} ({device.arn})")
Company | Processor | Qubits | Framework | Processors |
---|---|---|---|---|
QuEra | Aquila | 256 | Braket | braket.aquila , arn:aws:braket:us-east-1::device/qpu/quera/Aquila |
IonQ | Aria | 25 | Braket | arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1 |
IQM | Garnet | 20 | Braket | arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet |
Disclaimer: This list of backends is subject to change at any time.
For more accurate and up-to-date information, please refer to the Amazon Braket documentation
Tasksā
Run a Taskā
import strangeworks as sw
from braket.circuits import Circuit
from strangeworks_braket import StrangeworksDevice
sw.authenticate(api_key="api-key")
# create a simple quantum circuit
bell_state = Circuit().h(0).cnot(0, 1)
# Choose a device (an AWS-hosted simulator in this case)
tn1 = StrangeworksDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
# Execute the circuit
print("\nš¤ Executing Circuit...\n")
task = tn1.run(bell_state, 1000)
# At this point, the job is running on the Strangeworks Platform.
# You can check the status of the job in the Portal, even if
# stop this script.
print(f"ā³ Job {task.id} submitted!\n")
# Lots of good info in here
result = task.result()
# View the counts (also visible in the Portal in a chart š)
print(f"š š Counts: {result.measurement_counts}\n")
š„³ Success! You may view your job in the portal.
š Something went wrong? Find us in Slack!
Cancel a Taskā
You can cancel a task using the cancel
method. This will stop the task and prevent further charges although you may still be charged for the time the task was running.
from strangeworks_braket import StrangeworksDevice
from braket.circuits import Circuit
device = StrangeworksDevice("arn:aws:braket:us-east-1::device/qpu/ionq/Aria-1")
circuit = Circuit().h(0).cnot(0, 1)
task = device.run(circuit, shots=2500)
# Cancel the job
task.cancel()
Hybrid Jobsā
Hybrid jobs allow for the integration of classical and quantum computing tasks. The execution of these tasks on the Strangeworks Platform is similar to Braket Hybrid Jobs with a few minor differences.
An example script is shown below which will run a simple bell state circuit a number of times given by the input parameter num_iter
.
The form of the script has to follow a number of guidelines:
- The script must contain a function called main that takes no inputs,
def main()
. The inputs will be read in by theload_hyperparameters()
, see example below. This will be the entry point for the aws job. - The script must contain only one function called main
- The braket tracker must be imported,
from braket.tracking import Tracker
- The braket tracker must be started on the line right after
def main():
or immediately following any comments afterdef main():
- The braket save job result function must be imported
from braket.jobs import save_job_result
- The results of the tracker must saved using the
save_job_result
function from braket by including"task summary": t.quantum_tasks_statistics(),
in the output dictionary. - Nothing can follow
save_job_result
in the functionmain()
To run the examples, first save the below script as braket_hybrid_script.py
or download it here: braket_hybrid_script.py
import json
import os
from braket.aws import AwsDevice
from braket.circuits import Circuit
from braket.jobs import save_job_result
from braket.tracking import Tracker
def main():
"""
Example Hybrid Job File
"""
t = Tracker().start()
device_arn = os.environ["AMZN_BRAKET_DEVICE_ARN"]
# Initialise device
device = AwsDevice(device_arn)
print(f"Using device {device}")
hyperparams = load_hyperparameters()
print("Hyperparameters are:", hyperparams)
shots = int(hyperparams.get("shots"))
num_iter = int(hyperparams.get("num_iter"))
counts = []
bell = Circuit().h(0).cnot(0, 1)
for count in range(num_iter):
task = device.run(bell, shots=shots)
print(task.result().measurement_counts)
counts.append(task.result().measurement_counts)
# return results as strings
save_job_result(
{
"counts": json.dumps(counts),
"task summary": t.quantum_tasks_statistics(),
"estimated cost": t.qpu_tasks_cost() + t.simulator_tasks_cost()
}
)
def load_hyperparameters():
"""Load the Hybrid Job hyperparameters"""
hp_file = os.environ["AMZN_BRAKET_HP_FILE"]
with open(hp_file) as f:
hyperparams = json.load(f)
return hyperparams
Run a Hybrid Jobā
Hereās how the task is implemented using the Strangeworks SDK. For an example of running a simple hybrid job using Amazon Braket see Hybrid Jobs:
The key differences between Strangeworks and Braket for job submission are:
In Braket, the job creation process involves using the
AwsQuantumJob.create()
function and explicitly specifying parameters such as the device, source module, entry point, and hyperparameters.In Strangeworks, the
run_hybrid()
method is used for job submission, with the source module path and hyperparameters passed directly as arguments.
These differences highlight how Strangeworks aims to streamline the job submission process and make it more accessible for users:
import strangeworks
from strangeworks_braket import StrangeworksDevice
# Authenticate with your Strangeworks API key
strangeworks.authenticate(api_key="your-api-key")
# Initialize the quantum device
device = StrangeworksDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
# Submit the hybrid job
soure_module = "./braket_hybrid_script.py"
hyperparameters = {"shots": 100, "num_iter": 5}
sw_job = device.run_hybrid(soure_module, hyperparameters)
# Retrieve the job result
result = sw_job.result()
print(result)
š„³ Success! You may view your job in the portal.
š Something went wrong? Find us in Slack!
Cancel a Hybrid Jobā
For hybrid jobs, the cancel command terminates the classical hybrid job container immediately and does a best effort to cancel all of the related quantum tasks that are still in a non-terminal state. This will stop the job and prevent further charges although some charges may still apply for the work that has already been done. The job status will be updated to CANCELLED
in the portal.
from strangeworks_braket import StrangeworksDevice
device = StrangeworksDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
soure_module = "./braket_hybrid_script.py"
hyperparameters = {"shots": 100, "num_iter": 5}
sw_job = device.run_hybrid(soure_module, hyperparameters)
# Cancel the job
sw_job.cancel()
Advanced Featuresā
Error Mitigationā
Error mitigation techniques on IonQ Aria
import strangeworks as sw
from strangeworks_braket import StrangeworksDevice
from braket.circuits import Circuit
from braket.error_mitigation import Debias
sw.authenticate('api-key')
device = StrangeworksDevice("ionq_aria")
circuit = Circuit().h(0).cnot(0, 1)
task = device.run(circuit, shots=2500, device_parameters={"errorMitigation": Debias()})
result = task.result()
print(result.measurement_counts)
š„³ Success! You may view your job in the portal.
š Something went wrong? Find us in Slack!
Pulse Controlā
Pulse control on Braket is supported by using StrangeworksDevice
Qubit Spectroscopyā
The following example demonstrates how to perform qubit spectroscopy using a Gaussian waveform.
import strangeworks as sw
from strangeworks_braket import StrangeworksDevice
from braket.pulse import GaussianWaveform, PulseSequence
from braket.parametric import FreeParameter
sw.authenticate(api_key="your-api-key")
device = StrangeworksDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2")
if device.status == "ONLINE":
device_name = "ankaa"
experiment_configuration = {
"ankaa": {
"device_arn": "arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2",
"qubit": 3,
"drive_frame": "Transmon_3_charge_tx",
"readout_frame": "Transmon_3_readout_rx",
"spectroscopy_wf": GaussianWaveform(100e-9, 25e-9, 0.1, True),
"rabi_wf": GaussianWaveform(
FreeParameter("length"), FreeParameter("length") * 0.25, 0.2, True
),
},
}
drive_frame = device.frames[experiment_configuration[device_name]["drive_frame"]]
readout_frame = device.frames[experiment_configuration[device_name]["readout_frame"]]
waveform = experiment_configuration[device_name]["spectroscopy_wf"]
frequency = FreeParameter("frequency")
pulse_sequence = (
PulseSequence()
.set_frequency(drive_frame, frequency)
.play(drive_frame, waveform)
.capture_v0(readout_frame)
)
span = 75e6
N_shots = 100
qubit_spectroscopy_sequences = pulse_sequence(frequency=drive_frame.frequency - span / 2)
task = device.run(qubit_spectroscopy_sequences, shots=N_shots)
print(task.result().measurement_counts)
Custom Gate with Pulseā
The following example demonstrates how to create a custom single-qubit gate using Gaussian waveforms.
import strangeworks as sw
from strangeworks_braket import StrangeworksDevice
import braket.circuits.circuit as circuit
from braket.pulse import GaussianWaveform, PulseSequence
from braket.parametric import FreeParameter
from braket.circuits import Circuit
sw.authenticate(api_key="api-key")
device = StrangeworksDevice("arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2")
if device.status == "ONLINE":
qubit = 3
drive_frame = device.frames[f"Transmon_{qubit}_charge_tx"]
width = 5e-9
length = 40e-9
x90_amplitude = 0.9
x90 = GaussianWaveform(length, width, x90_amplitude, False)
lambda_ = FreeParameter("lambda_")
theta = FreeParameter("theta")
phi = FreeParameter("phi")
U_sequence = (
PulseSequence()
.shift_phase(drive_frame, np.pi / 2 - lambda_)
.play(drive_frame, x90)
.shift_phase(drive_frame, theta - np.pi)
.play(drive_frame, x90)
.shift_phase(drive_frame, np.pi / 2 - phi)
)
@circuit.subroutine(register=True)
def U_pulses(theta, phi, lambda_):
return Circuit().pulse_gate(
[qubit],
pulse_sequence=U_sequence(theta=theta, phi=phi, lambda_=lambda_),
)
nb_shots = 500
task = device.run(
Circuit().rx(4, np.pi / 2).rz(4, np.pi / 2).U_pulses(2 * np.pi, 0, 0),
shots=nb_shots,
disable_qubit_rewiring=True,
)
print(task.result().measurement_counts)
š„³ Success! You may view your job in the portal.
š Something went wrong? Find us in Slack!