Download
Download this file as Jupyter notebook: error_amplification.ipynb.
Error Amplification
The Rabi experiment (RabiExperiment
) is
performed in order to tune the amplitude of our pulses to perform rotation gates. This
step is crucial in our calibration workflow as imprecisions in its value lead to
rotation angles that do not match our expectations, resulting in errors that propagate
throughout our computations.
The Error Amplification experiment (also referred to as ping-pong in the literature) is a simple protocol to determine the accuracy of the rotation pulse amplitude. It relies on a simple concept: any given number of \(\pi\) pulse pairs should get the system back to its initial state. If the effective rotation angle is not exactly \(\pi\), increasing the number of \(\pi\) pulse pairs accumulates the errors and increases the deviation.
[2]:
import numpy as np
import keysight.qcs as qcs
from keysight.qcs.experiments import ErrorAmplification, make_calibration_set
We start by initializing a qubit and defining an empty channel mapper to create a new
instance of the ErrorAmplification
class. We
use the make_calibration_set()
function that
creates a calibration set for the given amount of qubit containing the linkers for the
RX
, Z
and measurement gates.
[3]:
# set the following to True when connected to hardware
run_on_hw = False
n_qubits = 1
qubits = qcs.Qudits(range(n_qubits))
calibration_set = make_calibration_set(n_qubits)
# generate an empty channel mapper
mapper = qcs.ChannelMapper("127.0.0.1")
# create Error Amplification experiment
error_amp_exp = ErrorAmplification(
backend=mapper, calibration_set=calibration_set, n_amplifications=3, qubits=qubits
)
n_amplifications
is an integer that determines the maximal number of \(\pi\)
pulse pairs sent to the driven system.
For instance, n_amplifications
= 3, 4 different pulse sequences are prepared (0,
2, 4 and 6 \(\pi\) pulses).
We can view the operations in the program with the following command:
[4]:
error_amp_exp.draw()
Program
Program
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
Measure on ('qudits', 0)
Parameters
|
We then configure the repetitions for this experiment and the pulse
amplitudes to sweep over by passing n_shots
and amplitudes array as
arguments of
configure_repetitions()
. We need
to provide the name of the amplitude variable in the calibration set that we are
tuning, as we did in RabiExperiment
.
Note that the amplitude values swept over can be different qubits but the number of
values should be the same.
[5]:
array = np.transpose([np.linspace(0.1, 1, 5)] * n_qubits)
amplitudes = qcs.Array(
"amplitudes",
value=array,
dtype=float,
)
error_amp_exp.configure_repetitions(
amplitudes=amplitudes, amplitude_name="x180_pulse_amplitudes", n_shots=1
)
Compiling this program to the waveform level using the
ParameterizedLinker
s in the calibration set
results in the following program:
[6]:
error_amp_exp.compiled_program.draw()
Program
Program
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
Delay on ('xy_pulse', 0)
Parameters
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Delay on ('readout_pulse', 0)
Parameters
|
Delay on ('readout_pulse', 0)
Parameters
|
RFWaveform on ('readout_pulse', 0)
Parameters
|
Delay on ('readout_pulse', 0)
Parameters
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Delay on ('readout_acquisition', 0)
Parameters
|
Delay on ('readout_acquisition', 0)
Parameters
|
Acquisition on ('readout_acquisition', 0)
Parameters
|
Delay on ('readout_acquisition', 0)
Parameters
|
We use the render()
method to visualize this with the
ChannelMapper
. The first index controls the number of
\(\pi\) pulse pairs displayed (up to n_amplifications
) whereas the second one
relates to the amplitude array provided when configuring the repetitions.
[7]:
error_amp_exp.compiled_program.render(
channel_subplots=False, sweep_index=(3, 1), lo_frequency=4.9e9, sample_rate=5.0e9
)
The first index control the number of pi pulse pairs and the second one controls the amplitude.
[8]:
error_amp_exp.compiled_program.render(
channel_subplots=False, sweep_index=(2, 4), lo_frequency=4.9e9, sample_rate=5.0e9
)
To execute this experiment, we can simply run
[9]:
if run_on_hw:
error_amp_exp.execute()
else:
# load in a previously executed version of this experiment
error_amp_exp = qcs.load("ErrorAmplification.qcs")
- ..note::
For the purposes of this demonstration, we added a second “ancilla” qubit to the ErrorAmplification program and connected the physical output channels for our qubit to the digizer associated with the ancilla to allow us to capture the full pulse sequence.
[10]:
error_amp_exp.draw()
Program
Program
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
RX
ParameterizedGate RX on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
PGATE
ParameterizedGate on ('qudits', 0)
Matrices
|
Measure on ('qudits', 0)
Parameters
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Measure on ('ancilla', 1)
Parameters
|
The compiled program in the waveform level is as follows:
[11]:
error_amp_exp.compiled_program.draw()
Program
Program
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
RFWaveform on ('xy_pulse', 0)
Parameters
|
Delay on ('xy_pulse', 0)
Parameters
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Delay on ('readout_pulse', 0)
Parameters
|
Delay on ('readout_pulse', 0)
Parameters
|
RFWaveform on ('readout_pulse', 0)
Parameters
|
Delay on ('readout_pulse', 0)
Parameters
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Delay on ('readout_acquisition', 0)
Parameters
|
Delay on ('readout_acquisition', 0)
Parameters
|
Acquisition on ('readout_acquisition', 0)
Parameters
|
Delay on ('readout_acquisition', 0)
Parameters
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Acquisition on ('readout_acquisition', 1)
Parameters
|
We can visualize the generated pulses directly with the following command:
[12]:
error_amp_exp.plot_trace(channels=qcs.Qudits(1, "ancilla"))
This concludes the tutorial for running an error amplification experiment,
using the Keysight QCS System. For detailed information on all available
arguments and functionalities, please refer to the API documentation for
ErrorAmplification
.
Download
Download this file as Jupyter notebook: error_amplification.ipynb.