Pulse
qiskit.pulse
Qiskit-Pulse is a pulse-level quantum programming kit. This lower level of programming offers the user more control than programming with QuantumCircuit
s.
Extracting the greatest performance from quantum hardware requires real-time pulse-level instructions. Pulse answers that need: it enables the quantum physicist user to specify the exact time dynamics of an experiment. It is especially powerful for error mitigation techniques.
The input is given as arbitrary, time-ordered signals (see: Instructions) scheduled in parallel over multiple virtual hardware or simulator resources (see: Channels). The system also allows the user to recover the time dynamics of the measured output.
This is sufficient to allow the quantum physicist to explore and correct for noise in a quantum system.
Instructions
qiskit.pulse.instructions
The instructions
module holds the various Instruction
s which are supported by Qiskit Pulse. Instructions have operands, which typically include at least one Channel
specifying where the instruction will be applied.
Every instruction has a duration, whether explicitly included as an operand or implicitly defined. For instance, a ShiftPhase
instruction can be instantiated with operands phase and channel, for some float phase
and a Channel
channel
:
ShiftPhase(phase, channel)
The duration of this instruction is implicitly zero. On the other hand, the Delay
instruction takes an explicit duration:
Delay(duration, channel)
An instruction can be added to a Schedule
, which is a sequence of scheduled Pulse Instruction
s over many channels. Instruction
s and Schedule
s implement the same interface.
Acquire (duration, channel[, mem_slot, ...]) | The Acquire instruction is used to trigger the ADC associated with a particular qubit; e.g. |
Call (subroutine[, value_dict, name]) | Pulse Call instruction. |
Reference (name, *extra_keys) | Pulse compiler directive that refers to a subroutine. |
Delay (duration, channel[, name]) | A blocking instruction with no other effect. |
Play (pulse, channel[, name]) | This instruction is responsible for applying a pulse on a channel. |
RelativeBarrier (*channels[, name]) | Pulse RelativeBarrier directive. |
SetFrequency (frequency, channel[, name]) | Set the channel frequency. |
ShiftFrequency (frequency, channel[, name]) | Shift the channel frequency away from the current frequency. |
SetPhase (phase, channel[, name]) | The set phase instruction sets the phase of the proceeding pulses on that channel to phase radians. |
ShiftPhase (phase, channel[, name]) | The shift phase instruction updates the modulation phase of proceeding pulses played on the same Channel . |
Snapshot (label[, snapshot_type, name]) | An instruction targeted for simulators, to capture a moment in the simulation. |
TimeBlockade (duration, channel[, name]) | Pulse TimeBlockade directive. |
These are all instances of the same base class:
Instruction
class qiskit.pulse.instructions.Instruction(operands, name=None)
The smallest schedulable unit: a single instruction. It has a fixed duration and specified channels.
Instruction initializer.
Parameters
Pulse Library
qiskit.pulse.library
This library provides Pulse users with convenient methods to build Pulse waveforms.
A pulse programmer can choose from one of several Pulse Models such as Waveform
and SymbolicPulse
to create a pulse program. The Waveform
model directly stores the waveform data points in each class instance. This model provides the most flexibility to express arbitrary waveforms and allows a rapid prototyping of new control techniques. However, this model is typically memory inefficient and might be hard to scale to large-size quantum processors. Several waveform subclasses are defined by Waveform Pulse Representation, but a user can also directly instantiate the Waveform
class with samples
argument which is usually a complex numpy array or any kind of array-like data.
In contrast, the SymbolicPulse
model only stores the function and its parameters that generate the waveform in a class instance. It thus provides greater memory efficiency at the price of less flexibility in the waveform. This model also defines a small set of pulse subclasses in Parametric Pulse Representation which are commonly used in superconducting quantum processors. An instance of these subclasses can be serialized in the QPY Format while keeping the memory-efficient parametric representation of waveforms. Note that Waveform
object can be generated from an instance of a SymbolicPulse
which will set values for the parameters and sample the parametric expression to create the Waveform
.
Pulse Models
Waveform (samples[, name, epsilon, ...]) | A pulse specified completely by complex-valued samples; each sample is played for the duration of the backend cycle-time, dt. |
SymbolicPulse (pulse_type, duration[, ...]) | The pulse representation model with parameters and symbolic expressions. |
ParametricPulse (duration[, name, ...]) | The abstract superclass for parametric pulses. |
Waveform Pulse Representation
constant
qiskit.pulse.library.constant(duration, amp, name=None)
Generates constant-sampled Waveform
.
For amp
, samples from the function:
The function qiskit.pulse.library.discrete.constant()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including constant() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Constant(…).get_waveform(). Note that complex value support for the amp parameter is pending deprecation in the SymbolicPulse library. It is therefore recommended to use two float values for (amp, angle) instead of complex amp
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Complex pulse amplitude.
- name (str | None) – Name of pulse.
Return type
zero
qiskit.pulse.library.zero(duration, name=None)
Generates zero-sampled Waveform
.
Samples from the function:
The function qiskit.pulse.library.discrete.zero()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including zero() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Constant(amp=0,…).get_waveform().
Parameters
Return type
square
qiskit.pulse.library.square(duration, amp, freq=None, phase=0, name=None)
Generates square wave Waveform
.
For amp
, period
, and phase
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
with the convention .
The function qiskit.pulse.library.discrete.square()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including square() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Square(…).get_waveform(). Note that pulse.Square() does not support complex values for amp, and that the phase is defined differently. See documentation.
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude. Wave range is
amp
amp
. - freq (float) – Pulse frequency, units of 1./dt. If
None
defaults to 1./duration. - phase (float) – Pulse phase.
- name (str | None) – Name of pulse.
Return type
sawtooth
qiskit.pulse.library.sawtooth(duration, amp, freq=None, phase=0, name=None)
Generates sawtooth wave Waveform
.
For amp
, period
, and phase
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
where .
The function qiskit.pulse.library.discrete.sawtooth()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including sawtooth() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Sawtooth(…).get_waveform(). Note that pulse.Sawtooth() does not support complex values for amp. Instead, use two float values for (amp, angle). Also note that the phase is defined differently, such that 2*pi phase shifts by a full cycle.
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude. Wave range is
amp
amp
. - freq (float) – Pulse frequency, units of 1./dt. If
None
defaults to 1./duration. - phase (float) – Pulse phase.
- name (str | None) – Name of pulse.
Return type
Example
import matplotlib.pyplot as plt
from qiskit.pulse.library import sawtooth
import numpy as np
duration = 100
amp = 1
freq = 1 / duration
sawtooth_wave = np.real(sawtooth(duration, amp, freq).samples)
plt.plot(range(duration), sawtooth_wave)
plt.show()
triangle
qiskit.pulse.library.triangle(duration, amp, freq=None, phase=0, name=None)
Generates triangle wave Waveform
.
For amp
, period
, and phase
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
This a non-sinusoidal wave with linear ramping.
The function qiskit.pulse.library.discrete.triangle()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including triangle() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Triangle(…).get_waveform(). Note that pulse.Triangle() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude. Wave range is
amp
amp
. - freq (float) – Pulse frequency, units of 1./dt. If
None
defaults to 1./duration. - phase (float) – Pulse phase.
- name (str | None) – Name of pulse.
Return type
Example
import matplotlib.pyplot as plt
from qiskit.pulse.library import triangle
import numpy as np
duration = 100
amp = 1
freq = 1 / duration
triangle_wave = np.real(triangle(duration, amp, freq).samples)
plt.plot(range(duration), triangle_wave)
plt.show()
cos
qiskit.pulse.library.cos(duration, amp, freq=None, phase=0, name=None)
Generates cosine wave Waveform
.
For amp
, freq
, and phase
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
The function qiskit.pulse.library.discrete.cos()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including cos() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Cos(…).get_waveform(). Note that pulse.Cos() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude.
- freq (float) – Pulse frequency, units of 1/dt. If
None
defaults to single cycle. - phase (float) – Pulse phase.
- name (str | None) – Name of pulse.
Return type
sin
qiskit.pulse.library.sin(duration, amp, freq=None, phase=0, name=None)
Generates sine wave Waveform
.
For amp
, freq
, and phase
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
The function qiskit.pulse.library.discrete.sin()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including sin() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Sin(…).get_waveform(). Note that pulse.Sin() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude.
- freq (float) – Pulse frequency, units of 1/dt. If
None
defaults to single cycle. - phase (float) – Pulse phase.
- name (str | None) – Name of pulse.
Return type
gaussian
qiskit.pulse.library.gaussian(duration, amp, sigma, name=None, zero_ends=True)
Generates unnormalized gaussian Waveform
.
For amp
and sigma
, applies the midpoint
sampling strategy to generate a discrete pulse sampled from the continuous function:
with the center duration/2
.
If zero_ends==True
, each output sample is modified according to:
where is the value of the endpoint samples. This sets the endpoints to while preserving the amplitude at the center. If , is set to . By default, the endpoints are at x = -1, x = duration + 1
.
Integrated area under the full curve is amp * np.sqrt(2*np.pi*sigma**2)
The function qiskit.pulse.library.discrete.gaussian()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including gaussian() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Gaussian(…).get_waveform(). Note that complex value support for the amp parameter is pending deprecation in the SymbolicPulse library. It is therefore recommended to use two float values for (amp, angle) instead of complex amp
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude at
duration/2
. - sigma (float) – Width (standard deviation) of pulse.
- name (str | None) – Name of pulse.
- zero_ends (bool) – If True, zero ends at
x = -1, x = duration + 1
, but rescale to preserve amp.
Return type
gaussian_deriv
qiskit.pulse.library.gaussian_deriv(duration, amp, sigma, name=None)
Generates unnormalized gaussian derivative Waveform
.
For amp
and sigma
applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
i.e. the derivative of the Gaussian function, with center duration/2
.
The function qiskit.pulse.library.discrete.gaussian_deriv()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including gaussian_deriv() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.GaussianDeriv(…).get_waveform(). Note that pulse.GaussianDeriv() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude of corresponding Gaussian at the pulse center (
duration/2
). - sigma (float) – Width (standard deviation) of pulse.
- name (str | None) – Name of pulse.
Return type
sech
qiskit.pulse.library.sech(duration, amp, sigma, name=None, zero_ends=True)
Generates unnormalized sech Waveform
.
For amp
and sigma
, applies the midpoint
sampling strategy to generate a discrete pulse sampled from the continuous function:
with the center duration/2
.
If zero_ends==True
, each output sample is modified according to:
where is the value of the endpoint samples. This sets the endpoints to while preserving the amplitude at the center. If , is set to . By default, the endpoints are at x = -1, x = duration + 1
.
The function qiskit.pulse.library.discrete.sech()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including sech() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Sech(…).get_waveform(). Note that pulse.Sech() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude at duration/2.
- sigma (float) – Width (standard deviation) of pulse.
- name (str) – Name of pulse.
- zero_ends (bool) – If True, zero ends at
x = -1, x = duration + 1
, but rescale to preserve amp.
Return type
sech_deriv
qiskit.pulse.library.sech_deriv(duration, amp, sigma, name=None)
Generates unnormalized sech derivative Waveform
.
For amp
, sigma
, and center duration/2
, applies the midpoint sampling strategy to generate a discrete pulse sampled from the continuous function:
i.e. the derivative of .
The function qiskit.pulse.library.discrete.sech_deriv()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including sech_deriv() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.SechDeriv(…).get_waveform(). Note that pulse.SechDeriv() does not support complex values for amp. Instead, use two float values for (amp, angle).
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude at center.
- sigma (float) – Width (standard deviation) of pulse.
- name (str) – Name of pulse.
Return type
gaussian_square
qiskit.pulse.library.gaussian_square(duration, amp, sigma, risefall=None, width=None, name=None, zero_ends=True)
Generates gaussian square Waveform
.
For duration
, amp
, sigma
, and risefall
, applies the midpoint
sampling strategy to generate a discrete pulse sampled from the continuous function:
where is the Gaussian function sampled from in gaussian()
with amp
, , and sigma
. I.e. represents a square pulse with smooth Gaussian edges.
If zero_ends == True
, the samples for the Gaussian ramps are remapped as in gaussian()
.
The function qiskit.pulse.library.discrete.gaussian_square()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including gaussian_square() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.GaussianSquare(…).get_waveform(). Note that complex value support for the amp parameter is pending deprecation in the SymbolicPulse library. It is therefore recommended to use two float values for (amp, angle) instead of complex amp
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude.
- sigma (float) – Width (standard deviation) of Gaussian rise/fall portion of the pulse.
- risefall (float | None) – Number of samples over which pulse rise and fall happen. Width of square portion of pulse will be
duration-2*risefall
. - width (float | None) – The duration of the embedded square pulse. Only one of
width
orrisefall
should be specified as the functional form requireswidth = duration - 2 * risefall
. - name (str | None) – Name of pulse.
- zero_ends (bool) – If True, zero ends at
x = -1, x = duration + 1
, but rescale to preserve amp.
Raises
PulseError – If risefall
and width
arguments are inconsistent or not enough info.
Return type
drag
qiskit.pulse.library.drag(duration, amp, sigma, beta, name=None, zero_ends=True)
Generates Y-only correction DRAG Waveform
for standard nonlinear oscillator (SNO) [1].
For amp
, sigma
, and beta
, applies the midpoint
sampling strategy to generate a discrete pulse sampled from the continuous function:
where is the function sampled in gaussian()
, and is the function sampled in gaussian_deriv()
.
If zero_ends == True
, the samples from are remapped as in gaussian()
.
The function qiskit.pulse.library.discrete.drag()
is pending deprecation as of qiskit 0.25.0. It will be marked deprecated in a future release, and then removed no earlier than 3 months after the release date. The discrete pulses library, including drag() is pending deprecation. Instead, use the SymbolicPulse library to create the waveform with pulse.Drag(…).get_waveform(). Note that complex value support for the amp parameter is pending deprecation in the SymbolicPulse library. It is therefore recommended to use two float values for (amp, angle) instead of complex amp
References
Parameters
- duration (int) – Duration of pulse. Must be greater than zero.
- amp (complex) – Pulse amplitude at center
duration/2
. - sigma (float) – Width (standard deviation) of pulse.
- beta (float) – Y correction amplitude. For the SNO this is . Where is the relative coupling strength between the first excited and second excited states and is the detuning between the respective excited states.
- name (str | None) – Name of pulse.
- zero_ends (bool) – If True, zero ends at
x = -1, x = duration + 1
, but rescale to preserve amp.
Return type
Parametric Pulse Representation
Constant (duration, amp[, angle, name, ...]) | A simple constant pulse, with an amplitude value and a duration: |
Drag (duration, amp, sigma, beta[, angle, ...]) | The Derivative Removal by Adiabatic Gate (DRAG) pulse is a standard Gaussian pulse with an additional Gaussian derivative component and lifting applied. |
Gaussian (duration, amp, sigma[, angle, ...]) | A lifted and truncated pulse envelope shaped according to the Gaussian function whose mean is centered at the center of the pulse (duration / 2): |
GaussianSquare (duration, amp, sigma[, ...]) | A square pulse with a Gaussian shaped risefall on both sides lifted such that its first sample is zero. |
GaussianSquareDrag (duration, amp, sigma, beta) | A square pulse with a Drag shaped rise and fall |
gaussian_square_echo (duration, amp, sigma[, ...]) | An echoed Gaussian square pulse with an active tone overlaid on it. |
GaussianDeriv (duration, amp, sigma[, angle, ...]) | An unnormalized Gaussian derivative pulse. |
Sin (duration, amp, phase[, freq, angle, ...]) | A sinusoidal pulse. |
Cos (duration, amp, phase[, freq, angle, ...]) | A cosine pulse. |
Sawtooth (duration, amp, phase[, freq, ...]) | A sawtooth pulse. |
Triangle (duration, amp, phase[, freq, ...]) | A triangle wave pulse. |
Square (duration, amp, phase[, freq, angle, ...]) | A square wave pulse. |
Sech (duration, amp, sigma[, angle, name, ...]) | An unnormalized sech pulse. |
SechDeriv (duration, amp, sigma[, angle, ...]) | An unnormalized sech derivative pulse. |
Channels
qiskit.pulse.channels
Pulse is meant to be agnostic to the underlying hardware implementation, while still allowing low-level control. Therefore, our signal channels are virtual hardware channels. The backend which executes our programs is responsible for mapping these virtual channels to the proper physical channel within the quantum control hardware.
Channels are characterized by their type and their index. Channels include:
- transmit channels, which should subclass
PulseChannel
- receive channels, such as
AcquireChannel
- non-signal “channels” such as
SnapshotChannel
,MemorySlot
andRegisterChannel
.
Novel channel types can often utilize the ControlChannel
, but if this is not sufficient, new channel types can be created. Then, they must be supported in the PulseQobj schema and the assembler. Channels are characterized by their type and their index. See each channel type below to learn more.
DriveChannel (*args, **kwargs) | Drive channels transmit signals to qubits which enact gate operations. |
MeasureChannel (*args, **kwargs) | Measure channels transmit measurement stimulus pulses for readout. |
AcquireChannel (*args, **kwargs) | Acquire channels are used to collect data. |
ControlChannel (*args, **kwargs) | Control channels provide supplementary control over the qubit to the drive channel. |
RegisterSlot (*args, **kwargs) | Classical resister slot channels represent classical registers (low-latency classical memory). |
MemorySlot (*args, **kwargs) | Memory slot channels represent classical memory storage. |
SnapshotChannel (*args, **kwargs) | Snapshot channels are used to specify instructions for simulators. |
All channels are children of the same abstract base class:
Channel
class qiskit.pulse.channels.Channel(*args, **kwargs)
Base class of channels. Channels provide a Qiskit-side label for typical quantum control hardware signal channels. The final label -> physical channel mapping is the responsibility of the hardware backend. For instance, DriveChannel(0)
holds instructions which the backend should map to the signal line driving gate operations on the qubit labeled (indexed) 0.
When serialized channels are identified by their serialized name <prefix><index>
. The type of the channel is interpreted from the prefix, and the index often (but not always) maps to the qubit index. All concrete channel classes must have a prefix
class attribute (and instances of that class have an index attribute). Base classes which have prefix
set to None
are prevented from being instantiated.
To implement a new channel inherit from Channel
and provide a unique string identifier for the prefix
class attribute.
Channel class.
Parameters
index – Index of channel.
Schedules
Schedules are Pulse programs. They describe instruction sequences for the control hardware. The Schedule is one of the most fundamental objects to this pulse-level programming module. A Schedule
is a representation of a program in Pulse. Each schedule tracks the time of each instruction occuring in parallel over multiple signal channels.
Schedule (*schedules[, name, metadata]) | A quantum program schedule with exact time constraints for its instructions, operating over all input signal channels and supporting special syntaxes for building. |
ScheduleBlock ([name, metadata, ...]) | Time-ordered sequence of instructions with alignment context. |
Pulse Transforms
qiskit.pulse.transforms
The pulse transforms provide transformation routines to reallocate and optimize pulse programs for backends.
Alignments
The alignment transforms define alignment policies of instructions in ScheduleBlock
. These transformations are called to create Schedule
s from ScheduleBlock
s.
AlignEquispaced (duration) | Align instructions with equispaced interval within a specified duration. |
AlignFunc (duration, func) | Allocate instructions at position specified by callback function. |
AlignLeft () | Align instructions in as-soon-as-possible manner. |
AlignRight () | Align instructions in as-late-as-possible manner. |
AlignSequential () | Align instructions sequentially. |
These are all subtypes of the abstract base class AlignmentKind
.
AlignmentKind
class qiskit.pulse.transforms.AlignmentKind(context_params)
An abstract class for schedule alignment.
Create new context.
Canonicalization
The canonicalization transforms convert schedules to a form amenable for execution on OpenPulse backends.
add_implicit_acquires
qiskit.pulse.transforms.add_implicit_acquires(schedule, meas_map)
Return a new schedule with implicit acquires from the measurement mapping replaced by explicit ones.
Since new acquires are being added, Memory Slots will be set to match the qubit index. This may overwrite your specification.
Parameters
- schedule (Schedule |Instruction) – Schedule to be aligned.
- meas_map (List[List[int]]) – List of lists of qubits that are measured together.
Returns
A Schedule
with the additional acquisition instructions.
Return type
align_measures
qiskit.pulse.transforms.align_measures(schedules, inst_map=None, cal_gate='u3', max_calibration_duration=None, align_time=None, align_all=True)
Return new schedules where measurements occur at the same physical time.
This transformation will align the first Acquire
on every channel to occur at the same time.
Minimum measurement wait time (to allow for calibration pulses) is enforced and may be set with max_calibration_duration
.
By default only instructions containing a AcquireChannel
or MeasureChannel
will be shifted. If you wish to keep the relative timing of all instructions in the schedule set align_all=True
.
This method assumes that MeasureChannel(i)
and AcquireChannel(i)
correspond to the same qubit and the acquire/play instructions should be shifted together on these channels.
from qiskit import pulse
from qiskit.pulse import transforms
d0 = pulse.DriveChannel(0)
m0 = pulse.MeasureChannel(0)
a0 = pulse.AcquireChannel(0)
mem0 = pulse.MemorySlot(0)
sched = pulse.Schedule()
sched.append(pulse.Play(pulse.Constant(10, 0.5), d0), inplace=True)
sched.append(pulse.Play(pulse.Constant(10, 1.), m0).shift(sched.duration), inplace=True)
sched.append(pulse.Acquire(20, a0, mem0).shift(sched.duration), inplace=True)
sched_shifted = sched << 20
aligned_sched, aligned_sched_shifted = transforms.align_measures([sched, sched_shifted])
assert aligned_sched == aligned_sched_shifted
If it is desired to only shift acquisition and measurement stimulus instructions set the flag align_all=False
:
aligned_sched, aligned_sched_shifted = transforms.align_measures(
[sched, sched_shifted],
align_all=False,
)
assert aligned_sched != aligned_sched_shifted
Parameters
- schedules (Iterable[Schedule |Instruction]) – Collection of schedules to be aligned together
- inst_map (InstructionScheduleMap | None) – Mapping of circuit operations to pulse schedules
- cal_gate (str) – The name of the gate to inspect for the calibration time
- max_calibration_duration (int | None) – If provided, inst_map and cal_gate will be ignored
- align_time (int | None) – If provided, this will be used as final align time.
- align_all (bool | None) – Shift all instructions in the schedule such that they maintain their relative alignment with the shifted acquisition instruction. If
False
only the acquisition and measurement pulse instructions will be shifted.
Returns
The input list of schedules transformed to have their measurements aligned.
Raises
PulseError – If the provided alignment time is negative.
Return type
block_to_schedule
qiskit.pulse.transforms.block_to_schedule(block)
Convert ScheduleBlock
to Schedule
.
Parameters
block (ScheduleBlock) – A ScheduleBlock
to convert.
Returns
Scheduled pulse program.
Raises
- UnassignedDurationError – When any instruction duration is not assigned.
- PulseError – When the alignment context duration is shorter than the schedule duration.
Return type
This transform may insert barriers in between contexts.
compress_pulses
qiskit.pulse.transforms.compress_pulses(schedules)
Optimization pass to replace identical pulses.
Parameters
schedules (List[Schedule]) – Schedules to compress.
Returns
Compressed schedules.
Return type
flatten
qiskit.pulse.transforms.flatten(program)
Flatten (inline) any called nodes into a Schedule tree with no nested children.
Parameters
program (Schedule) – Pulse program to remove nested structure.
Returns
Flatten pulse program.
Raises
PulseError – When invalid data format is given.
Return type
inline_subroutines
qiskit.pulse.transforms.inline_subroutines(program)
Recursively remove call instructions and inline the respective subroutine instructions.
Assigned parameter values, which are stored in the parameter table, are also applied. The subroutine is copied before the parameter assignment to avoid mutation problem.
Parameters
program (Schedule |ScheduleBlock) – A program which may contain the subroutine, i.e. Call
instruction.
Returns
A schedule without subroutine.
Raises
PulseError – When input program is not valid data format.
Return type
pad
qiskit.pulse.transforms.pad(schedule, channels=None, until=None, inplace=False, pad_with=None)
Pad the input Schedule with Delay``s on all unoccupied timeslots until ``schedule.duration
or until
if not None
.
Parameters
- schedule (Schedule) – Schedule to pad.
- channels (Iterable[Channel] | None) – Channels to pad. Defaults to all channels in
schedule
if not provided. If the supplied channel is not a member ofschedule
it will be added. - until (int | None) – Time to pad until. Defaults to
schedule.duration
if not provided. - inplace (bool) – Pad this schedule by mutating rather than returning a new schedule.
- pad_with (Type[Instruction] | None) – Pulse
Instruction
subclass to be used for padding. Default toDelay
instruction.
Returns
The padded schedule.
Raises
PulseError – When non pulse instruction is set to pad_with.
Return type
remove_directives
qiskit.pulse.transforms.remove_directives(schedule)
Remove directives.
Parameters
schedule (Schedule) – A schedule to remove compiler directives.
Returns
A schedule without directives.
Return type
remove_trivial_barriers
qiskit.pulse.transforms.remove_trivial_barriers(schedule)
Remove trivial barriers with 0 or 1 channels.
Parameters
schedule (Schedule) – A schedule to remove trivial barriers.
Returns
A schedule without trivial barriers
Return type
schedule
DAG
The DAG transforms create DAG representation of input program. This can be used for optimization of instructions and equality checks.
block_to_dag
qiskit.pulse.transforms.block_to_dag(block)
Convert schedule block instruction into DAG.
ScheduleBlock
can be represented as a DAG as needed. For example, equality of two programs are efficiently checked on DAG representation.
with pulse.build() as sched1:
with pulse.align_left():
pulse.play(my_gaussian0, pulse.DriveChannel(0))
pulse.shift_phase(1.57, pulse.DriveChannel(2))
pulse.play(my_gaussian1, pulse.DriveChannel(1))
with pulse.build() as sched2:
with pulse.align_left():
pulse.shift_phase(1.57, pulse.DriveChannel(2))
pulse.play(my_gaussian1, pulse.DriveChannel(1))
pulse.play(my_gaussian0, pulse.DriveChannel(0))
Here the sched1 `` and ``sched2
are different implementations of the same program, but it is difficult to confirm on the list representation.
Another example is instruction optimization.
with pulse.build() as sched:
with pulse.align_left():
pulse.shift_phase(1.57, pulse.DriveChannel(1))
pulse.play(my_gaussian0, pulse.DriveChannel(0))
pulse.shift_phase(-1.57, pulse.DriveChannel(1))
In above program two shift_phase
instructions can be cancelled out because they are consecutive on the same drive channel. This can be easily found on the DAG representation.
Parameters
block ("ScheduleBlock") – A schedule block to be converted.
Returns
Instructions in DAG representation.
Raises
PulseError – When the context is invalid subclass.
Return type
Composite transform
A sequence of transformations to generate a target code.
target_qobj_transform
qiskit.pulse.transforms.target_qobj_transform(sched, remove_directives=True)
A basic pulse program transformation for OpenPulse API execution.
Parameters
- sched (ScheduleBlock |Schedule |Tuple[int, Instruction] | Instruction |Iterable[Tuple[int, Instruction] | Instruction]) – Input program to transform.
- remove_directives (bool) – Set True to remove compiler directives.
Returns
Transformed program for execution.
Return type
Pulse Builder
Use the pulse builder DSL to write pulse programs with an imperative syntax.
The pulse builder interface is still in active development. It may have breaking API changes without deprecation warnings in future releases until otherwise indicated.
The pulse builder provides an imperative API for writing pulse programs with less difficulty than the Schedule
API. It contextually constructs a pulse schedule and then emits the schedule for execution. For example, to play a series of pulses on channels is as simple as:
from qiskit import pulse
dc = pulse.DriveChannel
d0, d1, d2, d3, d4 = dc(0), dc(1), dc(2), dc(3), dc(4)
with pulse.build(name='pulse_programming_in') as pulse_prog:
pulse.play([1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1], d0)
pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], d1)
pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0], d2)
pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], d3)
pulse.play([1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0], d4)
pulse_prog.draw()
To begin pulse programming we must first initialize our program builder context with build()
, after which we can begin adding program statements. For example, below we write a simple program that play()
s a pulse:
from qiskit import execute, pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.play(pulse.Constant(100, 1.0), d0)
pulse_prog.draw()
The builder initializes a pulse.Schedule
, pulse_prog
and then begins to construct the program within the context. The output pulse schedule will survive after the context is exited and can be executed like a normal Qiskit schedule using qiskit.execute(pulse_prog, backend)
.
Pulse programming has a simple imperative style. This leaves the programmer to worry about the raw experimental physics of pulse programming and not constructing cumbersome data structures.
We can optionally pass a Backend
to build()
to enable enhanced functionality. Below, we prepare a Bell state by automatically compiling the required pulses from their gate-level representations, while simultaneously applying a long decoupling pulse to a neighboring qubit. We terminate the experiment with a measurement to observe the state we prepared. This program which mixes circuits and pulses will be automatically lowered to be run as a pulse program:
import math
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse3Q
# TODO: This example should use a real mock backend.
backend = FakeOpenPulse3Q()
d2 = pulse.DriveChannel(2)
with pulse.build(backend) as bell_prep:
pulse.u2(0, math.pi, 0)
pulse.cx(0, 1)
with pulse.build(backend) as decoupled_bell_prep_and_measure:
# We call our bell state preparation schedule constructed above.
with pulse.align_right():
pulse.call(bell_prep)
pulse.play(pulse.Constant(bell_prep.duration, 0.02), d2)
pulse.barrier(0, 1, 2)
registers = pulse.measure_all()
decoupled_bell_prep_and_measure.draw()
With the pulse builder we are able to blend programming on qubits and channels. While the pulse schedule is based on instructions that operate on channels, the pulse builder automatically handles the mapping from qubits to channels for you.
In the example below we demonstrate some more features of the pulse builder:
import math
from qiskit import pulse, QuantumCircuit
from qiskit.pulse import library
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
# Create a pulse.
gaussian_pulse = library.gaussian(10, 1.0, 2)
# Get the qubit's corresponding drive channel from the backend.
d0 = pulse.drive_channel(0)
d1 = pulse.drive_channel(1)
# Play a pulse at t=0.
pulse.play(gaussian_pulse, d0)
# Play another pulse directly after the previous pulse at t=10.
pulse.play(gaussian_pulse, d0)
# The default scheduling behavior is to schedule pulses in parallel
# across channels. For example, the statement below
# plays the same pulse on a different channel at t=0.
pulse.play(gaussian_pulse, d1)
# We also provide pulse scheduling alignment contexts.
# The default alignment context is align_left.
# The sequential context schedules pulse instructions sequentially in time.
# This context starts at t=10 due to earlier pulses above.
with pulse.align_sequential():
pulse.play(gaussian_pulse, d0)
# Play another pulse after at t=20.
pulse.play(gaussian_pulse, d1)
# We can also nest contexts as each instruction is
# contained in its local scheduling context.
# The output of a child context is a context-schedule
# with the internal instructions timing fixed relative to
# one another. This is schedule is then called in the parent context.
# Context starts at t=30.
with pulse.align_left():
# Start at t=30.
pulse.play(gaussian_pulse, d0)
# Start at t=30.
pulse.play(gaussian_pulse, d1)
# Context ends at t=40.
# Alignment context where all pulse instructions are
# aligned to the right, ie., as late as possible.
with pulse.align_right():
# Shift the phase of a pulse channel.
pulse.shift_phase(math.pi, d1)
# Starts at t=40.
pulse.delay(100, d0)
# Ends at t=140.
# Starts at t=130.
pulse.play(gaussian_pulse, d1)
# Ends at t=140.
# Acquire data for a qubit and store in a memory slot.
pulse.acquire(100, 0, pulse.MemorySlot(0))
# We also support a variety of macros for common operations.
# Measure all qubits.
pulse.measure_all()
# Delay on some qubits.
# This requires knowledge of which channels belong to which qubits.
# delay for 100 cycles on qubits 0 and 1.
pulse.delay_qubits(100, 0, 1)
# Call a quantum circuit. The pulse builder lazily constructs a quantum
# circuit which is then transpiled and scheduled before inserting into
# a pulse schedule.
# NOTE: Quantum register indices correspond to physical qubit indices.
qc = QuantumCircuit(2, 2)
qc.cx(0, 1)
pulse.call(qc)
# Calling a small set of standard gates and decomposing to pulses is
# also supported with more natural syntax.
pulse.u3(0, math.pi, 0, 0)
pulse.cx(0, 1)
# It is also be possible to call a preexisting schedule
tmp_sched = pulse.Schedule()
tmp_sched += pulse.Play(gaussian_pulse, d0)
pulse.call(tmp_sched)
# We also support:
# frequency instructions
pulse.set_frequency(5.0e9, d0)
# phase instructions
pulse.shift_phase(0.1, d0)
# offset contexts
with pulse.phase_offset(math.pi, d0):
pulse.play(gaussian_pulse, d0)
The above is just a small taste of what is possible with the builder. See the rest of the module documentation for more information on its capabilities.
build
qiskit.pulse.builder.build(backend=None, schedule=None, name=None, default_alignment='left', default_transpiler_settings=None, default_circuit_scheduler_settings=None)
Create a context manager for launching the imperative pulse builder DSL.
To enter a building context and starting building a pulse program:
from qiskit import execute, pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.play(pulse.Constant(100, 0.5), d0)
While the output program pulse_prog
cannot be executed as we are using a mock backend. If a real backend is being used, executing the program is done with:
qiskit.execute(pulse_prog, backend)
Parameters
- backend (Backend) – A Qiskit backend. If not supplied certain builder functionality will be unavailable.
- schedule (ScheduleBlock | None) – A pulse
ScheduleBlock
in which your pulse program will be built. - name (str | None) – Name of pulse program to be built.
- default_alignment (str |AlignmentKind | None) – Default scheduling alignment for builder. One of
left
,right
,sequential
or an alignment context. - default_transpiler_settings (Dict[str, Any] | None) – Default settings for the transpiler.
- default_circuit_scheduler_settings (Dict[str, Any] | None) – Default settings for the circuit to pulse scheduler.
Returns
A new builder context which has the active builder initialized.
Return type
Channels
Methods to return the correct channels for the respective qubit indices.
from qiskit import pulse
from qiskit.providers.fake_provider import FakeArmonk
backend = FakeArmonk()
with pulse.build(backend) as drive_sched:
d0 = pulse.drive_channel(0)
print(d0)
DriveChannel(0)
acquire_channel
qiskit.pulse.builder.acquire_channel(qubit)
Return AcquireChannel
for qubit
on the active builder backend.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
assert pulse.acquire_channel(0) == pulse.AcquireChannel(0)
Requires the active builder context to have a backend set.
Return type
control_channels
qiskit.pulse.builder.control_channels(*qubits)
Return ControlChannel
for qubit
on the active builder backend.
Return the secondary drive channel for the given qubit – typically utilized for controlling multi-qubit interactions.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
assert pulse.control_channels(0, 1) == [pulse.ControlChannel(0)]
Requires the active builder context to have a backend set.
Parameters
qubits (Iterable[int]) – Tuple or list of ordered qubits of the form (control_qubit, target_qubit).
Returns
List of control channels associated with the supplied ordered list of qubits.
Return type
drive_channel
qiskit.pulse.builder.drive_channel(qubit)
Return DriveChannel
for qubit
on the active builder backend.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
assert pulse.drive_channel(0) == pulse.DriveChannel(0)
Requires the active builder context to have a backend set.
Return type
measure_channel
qiskit.pulse.builder.measure_channel(qubit)
Return MeasureChannel
for qubit
on the active builder backend.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
assert pulse.measure_channel(0) == pulse.MeasureChannel(0)
Requires the active builder context to have a backend set.
Return type
Instructions
Pulse instructions are available within the builder interface. Here’s an example:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeArmonk
backend = FakeArmonk()
with pulse.build(backend) as drive_sched:
d0 = pulse.drive_channel(0)
a0 = pulse.acquire_channel(0)
pulse.play(pulse.library.Constant(10, 1.0), d0)
pulse.delay(20, d0)
pulse.shift_phase(3.14/2, d0)
pulse.set_phase(3.14, d0)
pulse.shift_frequency(1e7, d0)
pulse.set_frequency(5e9, d0)
with pulse.build() as temp_sched:
pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), d0)
pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), d0)
pulse.call(temp_sched)
pulse.acquire(30, a0, pulse.MemorySlot(0))
drive_sched.draw()
acquire
qiskit.pulse.builder.acquire(duration, qubit_or_channel, register, **metadata)
Acquire for a duration
on a channel
and store the result in a register
.
Examples:
from qiskit import pulse
acq0 = pulse.AcquireChannel(0)
mem0 = pulse.MemorySlot(0)
with pulse.build() as pulse_prog:
pulse.acquire(100, acq0, mem0)
# measurement metadata
kernel = pulse.configuration.Kernel('linear_discriminator')
pulse.acquire(100, acq0, mem0, kernel=kernel)
The type of data acquire will depend on the execution meas_level
.
Parameters
- duration (int) – Duration to acquire data for
- qubit_or_channel (int |AcquireChannel) – Either the qubit to acquire data for or the specific
AcquireChannel
to acquire on. - register (StorageLocation) – Location to store measured result.
- metadata (Kernel | Discriminator) – Additional metadata for measurement. See
Acquire
for more information.
Raises
exceptions.PulseError – If the register type is not supported.
barrier
qiskit.pulse.builder.barrier(*channels_or_qubits, name=None)
Barrier directive for a set of channels and qubits.
This directive prevents the compiler from moving instructions across the barrier. Consider the case where we want to enforce that one pulse happens after another on separate channels, this can be done with:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
d0 = pulse.DriveChannel(0)
d1 = pulse.DriveChannel(1)
with pulse.build(backend) as barrier_pulse_prog:
pulse.play(pulse.Constant(10, 1.0), d0)
pulse.barrier(d0, d1)
pulse.play(pulse.Constant(10, 1.0), d1)
Of course this could have been accomplished with:
from qiskit.pulse import transforms
with pulse.build(backend) as aligned_pulse_prog:
with pulse.align_sequential():
pulse.play(pulse.Constant(10, 1.0), d0)
pulse.play(pulse.Constant(10, 1.0), d1)
barrier_pulse_prog = transforms.target_qobj_transform(barrier_pulse_prog)
aligned_pulse_prog = transforms.target_qobj_transform(aligned_pulse_prog)
assert barrier_pulse_prog == aligned_pulse_prog
The barrier allows the pulse compiler to take care of more advanced scheduling alignment operations across channels. For example in the case where we are calling an outside circuit or schedule and want to align a pulse at the end of one call:
import math
d0 = pulse.DriveChannel(0)
with pulse.build(backend) as pulse_prog:
with pulse.align_right():
pulse.x(1)
# Barrier qubit 1 and d0.
pulse.barrier(1, d0)
# Due to barrier this will play before the gate on qubit 1.
pulse.play(pulse.Constant(10, 1.0), d0)
# This will end at the same time as the pulse above due to
# the barrier.
pulse.x(1)
Requires the active builder context to have a backend set if qubits are barriered on.
Parameters
call
qiskit.pulse.builder.call(target, name=None, value_dict=None, **kw_params)
Call the subroutine within the currently active builder context with arbitrary parameters which will be assigned to the target program.
If the target
program is a ScheduleBlock
, then a Reference
instruction will be created and appended to the current context. The target
program will be immediately assigned to the current scope as a subroutine. If the target
program is Schedule
, it will be wrapped by the Call
instruction and appended to the current context to avoid a mixed representation of ScheduleBlock
and Schedule
. If the target
program is a QuantumCircuit
it will be scheduled and the new Schedule
will be added as a Call
instruction.
Examples
- Calling a schedule block (recommended)
from qiskit import circuit, pulse
from qiskit.providers.fake_provider import FakeBogotaV2
backend = FakeBogotaV2()
with pulse.build() as x_sched:
pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))
with pulse.build() as pulse_prog:
pulse.call(x_sched)
print(pulse_prog)
ScheduleBlock(
ScheduleBlock(
Play(
Gaussian(duration=160, amp=(0.1+0j), sigma=40),
DriveChannel(0)
),
name="block0",
transform=AlignLeft()
),
name="block1",
transform=AlignLeft()
)
The actual program is stored in the reference table attached to the schedule.
print(pulse_prog.references)
ReferenceManager:
- ('block0', '634b3b50bd684e26a673af1fbd2d6c81'): ScheduleBlock(Play(Gaussian(...
In addition, you can call a parameterized target program with parameter assignment.
amp = circuit.Parameter("amp")
with pulse.build() as subroutine:
pulse.play(pulse.Gaussian(160, amp, 40), pulse.DriveChannel(0))
with pulse.build() as pulse_prog:
pulse.call(subroutine, amp=0.1)
pulse.call(subroutine, amp=0.3)
print(pulse_prog)
ScheduleBlock(
ScheduleBlock(
Play(
Gaussian(duration=160, amp=(0.1+0j), sigma=40),
DriveChannel(0)
),
name="block2",
transform=AlignLeft()
),
ScheduleBlock(
Play(
Gaussian(duration=160, amp=(0.3+0j), sigma=40),
DriveChannel(0)
),
name="block2",
transform=AlignLeft()
),
name="block3",
transform=AlignLeft()
)
If there is a name collision between parameters, you can distinguish them by specifying each parameter object in a python dictionary. For example,
amp1 = circuit.Parameter('amp')
amp2 = circuit.Parameter('amp')
with pulse.build() as subroutine:
pulse.play(pulse.Gaussian(160, amp1, 40), pulse.DriveChannel(0))
pulse.play(pulse.Gaussian(160, amp2, 40), pulse.DriveChannel(1))
with pulse.build() as pulse_prog:
pulse.call(subroutine, value_dict={amp1: 0.1, amp2: 0.3})
print(pulse_prog)
ScheduleBlock(
ScheduleBlock(
Play(Gaussian(duration=160, amp=(0.1+0j), sigma=40), DriveChannel(0)),
Play(Gaussian(duration=160, amp=(0.3+0j), sigma=40), DriveChannel(1)),
name="block4",
transform=AlignLeft()
),
name="block5",
transform=AlignLeft()
)
- Calling a schedule
x_sched = backend.instruction_schedule_map.get("x", (0,))
with pulse.build(backend) as pulse_prog:
pulse.call(x_sched)
print(pulse_prog)
ScheduleBlock(
Call(
Schedule(
(
0,
Play(
Drag(
duration=160,
amp=(0.18989731546729305+0j),
sigma=40,
beta=-1.201258305015517,
name='drag_86a8'
),
DriveChannel(0),
name='drag_86a8'
)
),
name="x"
),
name='x'
),
name="block6",
transform=AlignLeft()
)
Currently, the backend calibrated gates are provided in the form of Schedule
. The parameter assignment mechanism is available also for schedules. However, the called schedule is not treated as a reference.
- Calling a quantum circuit
backend = FakeBogotaV2()
qc = circuit.QuantumCircuit(1)
qc.x(0)
with pulse.build(backend) as pulse_prog:
pulse.call(qc)
print(pulse_prog)
ScheduleBlock(
Call(
Schedule(
(
0,
Play(
Drag(
duration=160,
amp=(0.18989731546729305+0j),
sigma=40,
beta=-1.201258305015517,
name='drag_86a8'
),
DriveChannel(0),
name='drag_86a8'
)
),
name="circuit-87"
),
name='circuit-87'
),
name="block7",
transform=AlignLeft()
)
Calling a circuit from a schedule is not encouraged. Currently, the Qiskit execution model is migrating toward the pulse gate model, where schedules are attached to circuits through the QuantumCircuit.add_calibration()
method.
Parameters
- target (QuantumCircuit |Schedule |ScheduleBlock | None) – Target circuit or pulse schedule to call.
- name (str | None) – Optional. A unique name of subroutine if defined. When the name is explicitly provided, one cannot call different schedule blocks with the same name.
- value_dict (Dict[ParameterExpression |float, ParameterExpression |float] | None) – Optional. Parameters assigned to the
target
program. If this dictionary is provided, thetarget
program is copied and then stored in the main built schedule and its parameters are assigned to the given values. This dictionary is keyed onParameter
objects, allowing parameter name collision to be avoided. - kw_params (ParameterExpression |float) – Alternative way to provide parameters. Since this is keyed on the string parameter name, the parameters having the same name are all updated together. If you want to avoid name collision, use
value_dict
withParameter
objects instead.
delay
qiskit.pulse.builder.delay(duration, channel, name=None)
Delay on a channel
for a duration
.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.delay(10, d0)
Parameters
play
qiskit.pulse.builder.play(pulse, channel, name=None)
Play a pulse
on a channel
.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.play(pulse.Constant(10, 1.0), d0)
Parameters
reference
qiskit.pulse.builder.reference(name, *extra_keys)
Refer to undefined subroutine by string keys.
A Reference
instruction is implicitly created and a schedule can be separately registered to the reference at a later stage.
from qiskit import pulse
with pulse.build() as main_prog:
pulse.reference("x_gate", "q0")
with pulse.build() as subroutine:
pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))
main_prog.assign_references(subroutine_dict={("x_gate", "q0"): subroutine})
Parameters
set_frequency
qiskit.pulse.builder.set_frequency(frequency, channel, name=None)
Set the frequency
of a pulse channel
.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.set_frequency(1e9, d0)
Parameters
set_phase
qiskit.pulse.builder.set_phase(phase, channel, name=None)
Set the phase
of a pulse channel
.
Examples:
import math
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.set_phase(math.pi, d0)
Parameters
shift_frequency
qiskit.pulse.builder.shift_frequency(frequency, channel, name=None)
Shift the frequency
of a pulse channel
.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.shift_frequency(1e9, d0)
Parameters
shift_phase
qiskit.pulse.builder.shift_phase(phase, channel, name=None)
Shift the phase
of a pulse channel
.
Examples:
import math
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
pulse.shift_phase(math.pi, d0)
Parameters
snapshot
qiskit.pulse.builder.snapshot(label, snapshot_type='statevector')
Simulator snapshot.
Examples:
from qiskit import pulse
with pulse.build() as pulse_prog:
pulse.snapshot('first', 'statevector')
Parameters
Contexts
Builder aware contexts that modify the construction of a pulse program. For example an alignment context like align_right()
may be used to align all pulses as late as possible in a pulse program.
from qiskit import pulse
d0 = pulse.DriveChannel(0)
d1 = pulse.DriveChannel(1)
with pulse.build() as pulse_prog:
with pulse.align_right():
# this pulse will start at t=0
pulse.play(pulse.Constant(100, 1.0), d0)
# this pulse will start at t=80
pulse.play(pulse.Constant(20, 1.0), d1)
pulse_prog.draw()
align_equispaced
qiskit.pulse.builder.align_equispaced(duration)
Equispaced alignment pulse scheduling context.
Pulse instructions within this context are scheduled with the same interval spacing such that the total length of the context block is duration
. If the total free duration
cannot be evenly divided by the number of instructions within the context, the modulo is split and then prepended and appended to the returned schedule. Delay instructions are automatically inserted in between pulses.
This context is convenient to write a schedule for periodical dynamic decoupling or the Hahn echo sequence.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
x90 = pulse.Gaussian(10, 0.1, 3)
x180 = pulse.Gaussian(10, 0.2, 3)
with pulse.build() as hahn_echo:
with pulse.align_equispaced(duration=100):
pulse.play(x90, d0)
pulse.play(x180, d0)
pulse.play(x90, d0)
hahn_echo.draw()
Parameters
duration (int |ParameterExpression) – Duration of this context. This should be larger than the schedule duration.
Yields
None
Return type
Notes
The scheduling is performed for sub-schedules within the context rather than channel-wise. If you want to apply the equispaced context for each channel, you should use the context independently for channels.
align_func
qiskit.pulse.builder.align_func(duration, func)
Callback defined alignment pulse scheduling context.
Pulse instructions within this context are scheduled at the location specified by arbitrary callback function position that takes integer index and returns the associated fractional location within [0, 1]. Delay instruction is automatically inserted in between pulses.
This context may be convenient to write a schedule of arbitrary dynamical decoupling sequences such as Uhrig dynamical decoupling.
Examples:
import numpy as np
from qiskit import pulse
d0 = pulse.DriveChannel(0)
x90 = pulse.Gaussian(10, 0.1, 3)
x180 = pulse.Gaussian(10, 0.2, 3)
def udd10_pos(j):
return np.sin(np.pi*j/(2*10 + 2))**2
with pulse.build() as udd_sched:
pulse.play(x90, d0)
with pulse.align_func(duration=300, func=udd10_pos):
for _ in range(10):
pulse.play(x180, d0)
pulse.play(x90, d0)
udd_sched.draw()
Parameters
- duration (int |ParameterExpression) – Duration of context. This should be larger than the schedule duration.
- func (Callable[[int], float]) – A function that takes an index of sub-schedule and returns the fractional coordinate of of that sub-schedule. The returned value should be defined within [0, 1]. The pulse index starts from 1.
Yields
None
Return type
Notes
The scheduling is performed for sub-schedules within the context rather than channel-wise. If you want to apply the numerical context for each channel, you need to apply the context independently to channels.
align_left
qiskit.pulse.builder.align_left()
Left alignment pulse scheduling context.
Pulse instructions within this context are scheduled as early as possible by shifting them left to the earliest available time.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
d1 = pulse.DriveChannel(1)
with pulse.build() as pulse_prog:
with pulse.align_left():
# this pulse will start at t=0
pulse.play(pulse.Constant(100, 1.0), d0)
# this pulse will start at t=0
pulse.play(pulse.Constant(20, 1.0), d1)
pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
assert pulse_prog.ch_start_time(d0) == pulse_prog.ch_start_time(d1)
Yields
None
Return type
ContextManager[None]
align_right
qiskit.pulse.builder.align_right()
Right alignment pulse scheduling context.
Pulse instructions within this context are scheduled as late as possible by shifting them right to the latest available time.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
d1 = pulse.DriveChannel(1)
with pulse.build() as pulse_prog:
with pulse.align_right():
# this pulse will start at t=0
pulse.play(pulse.Constant(100, 1.0), d0)
# this pulse will start at t=80
pulse.play(pulse.Constant(20, 1.0), d1)
pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
assert pulse_prog.ch_stop_time(d0) == pulse_prog.ch_stop_time(d1)
Yields
None
Return type
align_sequential
qiskit.pulse.builder.align_sequential()
Sequential alignment pulse scheduling context.
Pulse instructions within this context are scheduled sequentially in time such that no two instructions will be played at the same time.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
d1 = pulse.DriveChannel(1)
with pulse.build() as pulse_prog:
with pulse.align_sequential():
# this pulse will start at t=0
pulse.play(pulse.Constant(100, 1.0), d0)
# this pulse will also start at t=100
pulse.play(pulse.Constant(20, 1.0), d1)
pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
assert pulse_prog.ch_stop_time(d0) == pulse_prog.ch_start_time(d1)
Yields
None
Return type
circuit_scheduler_settings
qiskit.pulse.builder.circuit_scheduler_settings(**settings)
Set the currently active circuit scheduler settings for this context.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
print(pulse.active_circuit_scheduler_settings())
with pulse.circuit_scheduler_settings(method='alap'):
print(pulse.active_circuit_scheduler_settings())
{}
{'method': 'alap'}
Return type
ContextManager[None]
frequency_offset
qiskit.pulse.builder.frequency_offset(frequency, *channels, compensate_phase=False)
Shift the frequency of inputs channels on entry into context and undo on exit.
Examples:
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build(backend) as pulse_prog:
# shift frequency by 1GHz
with pulse.frequency_offset(1e9, d0):
pulse.play(pulse.Constant(10, 1.0), d0)
assert len(pulse_prog.instructions) == 3
with pulse.build(backend) as pulse_prog:
# Shift frequency by 1GHz.
# Undo accumulated phase in the shifted frequency frame
# when exiting the context.
with pulse.frequency_offset(1e9, d0, compensate_phase=True):
pulse.play(pulse.Constant(10, 1.0), d0)
assert len(pulse_prog.instructions) == 4
Parameters
- frequency (float) – Amount of frequency offset in Hz.
- channels (PulseChannel) – Channels to offset frequency of.
- compensate_phase (bool) – Compensate for accumulated phase accumulated with respect to the channels’ frame at its initial frequency.
Yields
None
Return type
ContextManager[None]
phase_offset
qiskit.pulse.builder.phase_offset(phase, *channels)
Shift the phase of input channels on entry into context and undo on exit.
Examples:
import math
from qiskit import pulse
d0 = pulse.DriveChannel(0)
with pulse.build() as pulse_prog:
with pulse.phase_offset(math.pi, d0):
pulse.play(pulse.Constant(10, 1.0), d0)
assert len(pulse_prog.instructions) == 3
Parameters
- phase (float) – Amount of phase offset in radians.
- channels (PulseChannel) – Channels to offset phase of.
Yields
None
Return type
ContextManager[None]
transpiler_settings
qiskit.pulse.builder.transpiler_settings(**settings)
Set the currently active transpiler settings for this context.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
print(pulse.active_transpiler_settings())
with pulse.transpiler_settings(optimization_level=3):
print(pulse.active_transpiler_settings())
{}
{'optimization_level': 3}
Return type
ContextManager[None]
Macros
Macros help you add more complex functionality to your pulse program.
from qiskit import pulse
from qiskit.providers.fake_provider import FakeArmonk
backend = FakeArmonk()
with pulse.build(backend) as measure_sched:
mem_slot = pulse.measure(0)
print(mem_slot)
MemorySlot(0)
measure
qiskit.pulse.builder.measure(qubits, registers=None)
Measure a qubit within the currently active builder context.
At the pulse level a measurement is composed of both a stimulus pulse and an acquisition instruction which tells the systems measurement unit to acquire data and process it. We provide this measurement macro to automate the process for you, but if desired full control is still available with acquire()
and play()
.
To use the measurement it is as simple as specifying the qubit you wish to measure:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
qubit = 0
with pulse.build(backend) as pulse_prog:
# Do something to the qubit.
qubit_drive_chan = pulse.drive_channel(0)
pulse.play(pulse.Constant(100, 1.0), qubit_drive_chan)
# Measure the qubit.
reg = pulse.measure(qubit)
For now it is not possible to do much with the handle to reg
but in the future we will support using this handle to a result register to build up ones program. It is also possible to supply this register:
with pulse.build(backend) as pulse_prog:
pulse.play(pulse.Constant(100, 1.0), qubit_drive_chan)
# Measure the qubit.
mem0 = pulse.MemorySlot(0)
reg = pulse.measure(qubit, mem0)
assert reg == mem0
Requires the active builder context to have a backend set.
Parameters
- qubits (List[int] | int) – Physical qubit to measure.
- registers (List[StorageLocation] | StorageLocation | None) – Register to store result in. If not selected the current behavior is to return the
MemorySlot
with the same index asqubit
. This register will be returned.
Returns
The register
the qubit measurement result will be stored in.
Return type
List[StorageLocation] | StorageLocation
measure_all
qiskit.pulse.builder.measure_all()
Measure all qubits within the currently active builder context.
A simple macro function to measure all of the qubits in the device at the same time. This is useful for handling device meas_map
and single measurement constraints.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
# Measure all qubits and return associated registers.
regs = pulse.measure_all()
Requires the active builder context to have a backend set.
Returns
The register
s the qubit measurement results will be stored in.
Return type
delay_qubits
qiskit.pulse.builder.delay_qubits(duration, *qubits)
Insert delays on all of the channels.Channel
s that correspond to the input qubits
at the same time.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse3Q
backend = FakeOpenPulse3Q()
with pulse.build(backend) as pulse_prog:
# Delay for 100 cycles on qubits 0, 1 and 2.
regs = pulse.delay_qubits(100, 0, 1, 2)
Requires the active builder context to have a backend set.
Parameters
Circuit Gates
To use circuit level gates within your pulse program call a circuit with call()
.
These will be removed in future versions with the release of a circuit builder interface in which it will be possible to calibrate a gate in terms of pulses and use that gate in a circuit.
import math
from qiskit import pulse
from qiskit.providers.fake_provider import FakeArmonk
backend = FakeArmonk()
with pulse.build(backend) as u3_sched:
pulse.u3(math.pi, 0, math.pi, 0)
cx
qiskit.pulse.builder.cx(control, target)
Call a CXGate
on the input physical qubits.
Calling gates directly within the pulse builder namespace will be deprecated in the future in favor of tight integration with a circuit builder interface which is under development.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
pulse.cx(0, 1)
u1
qiskit.pulse.builder.u1(theta, qubit)
Call a U1Gate
on the input physical qubit.
Calling gates directly within the pulse builder namespace will be deprecated in the future in favor of tight integration with a circuit builder interface which is under development.
Examples:
import math
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
pulse.u1(math.pi, 1)
u2
qiskit.pulse.builder.u2(phi, lam, qubit)
Call a U2Gate
on the input physical qubit.
Calling gates directly within the pulse builder namespace will be deprecated in the future in favor of tight integration with a circuit builder interface which is under development.
Examples:
import math
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
pulse.u2(0, math.pi, 1)
u3
qiskit.pulse.builder.u3(theta, phi, lam, qubit)
Call a U3Gate
on the input physical qubit.
Calling gates directly within the pulse builder namespace will be deprecated in the future in favor of tight integration with a circuit builder interface which is under development.
Examples:
import math
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
pulse.u3(math.pi, 0, math.pi, 1)
x
qiskit.pulse.builder.x(qubit)
Call a XGate
on the input physical qubit.
Calling gates directly within the pulse builder namespace will be deprecated in the future in favor of tight integration with a circuit builder interface which is under development.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend) as pulse_prog:
pulse.x(0)
Utilities
The utility functions can be used to gather attributes about the backend and modify how the program is built.
from qiskit import pulse
from qiskit.providers.fake_provider import FakeArmonk
backend = FakeArmonk()
with pulse.build(backend) as u3_sched:
print('Number of qubits in backend: {}'.format(pulse.num_qubits()))
samples = 160
print('There are {} samples in {} seconds'.format(
samples, pulse.samples_to_seconds(160)))
seconds = 1e-6
print('There are {} seconds in {} samples.'.format(
seconds, pulse.seconds_to_samples(1e-6)))
Number of qubits in backend: 1
There are 160 samples in 3.5555555555555554e-08 seconds
There are 1e-06 seconds in 4500 samples.
active_backend
qiskit.pulse.builder.active_backend()
Get the backend of the currently active builder context.
Returns
The active backend in the currently active
builder context.
Return type
Raises
exceptions.BackendNotSet – If the builder does not have a backend set.
active_transpiler_settings
qiskit.pulse.builder.active_transpiler_settings()
Return the current active builder context’s transpiler settings.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
transpiler_settings = {'optimization_level': 3}
with pulse.build(backend,
default_transpiler_settings=transpiler_settings):
print(pulse.active_transpiler_settings())
{'optimization_level': 3}
Return type
active_circuit_scheduler_settings
qiskit.pulse.builder.active_circuit_scheduler_settings()
Return the current active builder context’s circuit scheduler settings.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
circuit_scheduler_settings = {'method': 'alap'}
with pulse.build(
backend,
default_circuit_scheduler_settings=circuit_scheduler_settings):
print(pulse.active_circuit_scheduler_settings())
{'method': 'alap'}
Return type
num_qubits
qiskit.pulse.builder.num_qubits()
Return number of qubits in the currently active backend.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
print(pulse.num_qubits())
2
Requires the active builder context to have a backend set.
Return type
qubit_channels
qiskit.pulse.builder.qubit_channels(qubit)
Returns the set of channels associated with a qubit.
Examples:
from qiskit import pulse
from qiskit.providers.fake_provider import FakeOpenPulse2Q
backend = FakeOpenPulse2Q()
with pulse.build(backend):
print(pulse.qubit_channels(0))
{MeasureChannel(0), ControlChannel(0), DriveChannel(0), AcquireChannel(0), ControlChannel(1)}
Requires the active builder context to have a backend set.
A channel may still be associated with another qubit in this list such as in the case where significant crosstalk exists.
Return type
samples_to_seconds
qiskit.pulse.builder.samples_to_seconds(samples)
Obtain the time in seconds that will elapse for the input number of samples on the active backend.
Parameters
samples (int |ndarray) – Number of samples to convert to time in seconds.
Returns
The time that elapses in samples
.
Return type
seconds_to_samples
qiskit.pulse.builder.seconds_to_samples(seconds)
Obtain the number of samples that will elapse in seconds
on the active backend.
Rounds down.
Parameters
seconds (float |ndarray) – Time in seconds to convert to samples.
Returns
The number of samples for the time to elapse
Return type
Configuration
InstructionScheduleMap () | Mapping from QuantumCircuit qiskit.circuit.Instruction names and qubits to Schedule s. In particular, the mapping is formatted as type::. |
Exceptions
PulseError
exception qiskit.pulse.PulseError(*message)
Errors raised by the pulse module.
Set the error message.
BackendNotSet
exception qiskit.pulse.BackendNotSet(*message)
Raised if the builder context does not have a backend.
Set the error message.
NoActiveBuilder
exception qiskit.pulse.NoActiveBuilder(*message)
Raised if no builder context is active.
Set the error message.
UnassignedDurationError
exception qiskit.pulse.UnassignedDurationError(*message)
Raised if instruction duration is unassigned.
Set the error message.
UnassignedReferenceError
exception qiskit.pulse.UnassignedReferenceError(*message)
Raised if subroutine is unassigned.
Set the error message.