AWS Quantum Technologies Blog
Amazon Braket launches Braket Pulse to develop quantum programs at the pulse level
When experimenting on a quantum computer, customers often need to program at the lower-level language of the device. Today, we are launching Braket Pulse, a feature that provides pulse-level access to quantum processing units (QPUs) from two hardware providers on Amazon Braket, Rigetti Computing and Oxford Quantum Circuits (OQC). In this blog, we present an overview of pulse control on Amazon Braket.
Braket Pulse is a feature that enables you to develop quantum applications using pulses, the analog instructions that control the qubits of a QPU. Until now on Amazon Braket, you could only program circuits using predefined gates. While this is a popular and efficient abstraction, researchers interested in exploring noise, error mitigation, or developing novel analog quantum algorithms often require a deeper level of control over the QPU. With today’s launch, you can now use the Braket SDK and APIs to run programs using pulses, gates, or a combination of the two on Rigetti’s Aspen-M-2 and OQC’s Lucy.
Introduction to pulse programming
In the gate-based approach to quantum computing, QPUs implement a set of native gates, the set of computational operations that are directly supported by the hardware. Under the hood, these native gates are implemented by carefully calibrated analog control signals, or pulses, that act directly on the state of the qubits. Braket Pulse enables you to program QPUs directly at the level of these physical control signals to get unabridged access to the elementary components of the device. Practically, you will schedule time-dependent transient signals to modulate the strength, direction, and timing of electromagnetic fields that control the dynamics of qubits to realize the required quantum operations.
With these capabilities, you are no longer limited to the fixed set of predefined gates that are exposed by the hardware providers. This benefits a wide range of customers in the quantum community, including academic researchers and quantum algorithm developers who are interested in several aspects of pulse-level programming such as:
- improving the elementary operations by experimenting and adopting novel custom gate implementations or investigating emerging paradigms like quantum computing with qutrits;
- augmenting their quantum circuits with dynamical decoupling sequences to suppress unwanted noise effects or testing error-mitigation techniques such as Zero-noise extrapolation;
- designing analog quantum algorithms directly at the pulse level to reduce the gate abstraction overhead of digital algorithms.
Programming with Braket Pulse
Unlike quantum gates that abstract away several concepts of quantum physics, pulse-level control requires a deeper knowledge of interacting quantum systems in general, and hardware design specifically. It also calls for a new programming language beyond the gate-level that can express those hardware concepts, which we’ll explore in the following paragraph. We have chosen to base Braket Pulse on OpenPulse, the grammar extension of the OpenQASM 3 specification.
You first need to be familiar with some of these new concepts that are at the core of Braket Pulse. As pulse-level control is inherently close to hardware programming, we need to have a close description of the different channels, also known as ports, of the devices. Braket Pulse introduces the class Port
that is a software abstraction for pre-built physical QPU ports. Bound to ports, Frames
are the software abstractions representing physical frames of reference of the carrier signals and serve as support for scheduling waveforms. With Amazon Braket, you can instantiate predefined frames to prototype pulse sequences with minimal overhead. Here is an example using OQC’s Lucy device:
from braket.aws import AwsDevice
lucy_device = AwsDevice("arn:aws:braket:eu-west-2::device/qpu/oqc/Lucy")
drive_frame = lucy_device.frames["q0_drive"]
readout_frame = lucy_device.frames["r0_measure"]
Braket Pulse is part of the Braket SDK with which you can construct pulse sequences using the PulseSequence
class. PulseSequences
share many similarities with Circuits
, such as, defining the operation of a low-level program, recording the list of chronologically ordered quantum instructions, and being executable as standalone programs with a single call of the device.run()
function. PulseSequence
exposes a user interface to schedule waveforms on desired frames via functions such as play
(adds the waveform to the PulseSequence
data structure), capture_v0
(reads the state of a qubit via a predefined routine), or barrier
(synchronizes multiple frames). Here we present a short pulse sequence that rotates the qubit vector around the y-axis (realizing a quantum process close to the RY gate) and measures the qubit in the measurement basis.
from braket.pulse import PulseSequence, GaussianWaveform
import math
# Create a Gaussian waveform with a pulse length of 100ns,
# a width of 25ns and an amplitude of 0.1 (normed)
gaussian = GaussianWaveform(length=100e-9, sigma=25e-9, amplitude=0.1)
pulse_sequence = (
PulseSequence() # instantiate a new pulse sequence object
.set_phase(drive_frame, math.pi/2) # set the frame’s phase to pi/2
.play(drive_frame, gaussian) # add a play instruction with a Gaussian waveform
.barrier([drive_frame, readout_frame]) # synchronize both frames
.capture_v0(readout_frame) # read out the state of the qubit
)
task = lucy_device.run(pulse_sequence, shots=100)
counts = task.result().measurement_counts
print(counts)
Counter({'1': 72, '0': 28})
Integration with quantum circuits
You can also specify a gate directly in terms of its pulse sequence by using the pulse_gate()
method. Thus, you can incorporate your own custom gate with standard gates in the same circuit to test the performance improvement for your algorithm. Here is how you can construct a delay gate that times gate operations according to defined delay parameters and insert it in your circuit:
from braket.circuits import Circuit
from braket.parametric import FreeParameter
wait = PulseSequence().delay(drive_frame, FreeParameter("delay"))
circuit = Circuit().rx(0, math.pi/2).pulse_gate(0, wait).rx(0, math.pi/2)
task = lucy_device.run(circuit(delay=1e-6), shots=100)
print(task.result().measurement_counts)
Counter({'1': 41, '0': 9})
The pulse module of the Braket SDK is built on top of OQpy, a python binding for OpenPulse that we open sourced as part of today’s launch. Reinforcing our commitment to enable interoperability between different end-user libraries and devices, we are proud to contribute it back to the OpenQASM project. We are also excited to give customers the maximal flexibility to program circuits using the Amazon Braket SDK, OQpy, or directly using OpenQASM 3 on Amazon Braket. To learn more about OQpy, check out this blog post.
Conclusion
In this blog we have introduced you to Braket Pulse, a feature which gives you pulse-level control of quantum devices on Amazon Braket. With this new release, you can start developing your quantum programs with better tunability and potentially higher performance than with gate-based circuits alone. To explore how pulse-level access can enable you to get the most out of today’s quantum hardware by studying the physics of superconducting qubits or developing your own custom gates, see our example notebooks or refer to our documentation.