Download
Download this file as Jupyter notebook: qubit_dynamical_decoupling.ipynb.
Dynamical decoupling
Dynamical decoupling is a simple error suppression strategy in quantum computing systems in which a series of pulses with certain intervals are applied to the qubits to effectively “decouple” them from their environment, thus improving decoherence times.
The type of interaction with the environment typically determines what kind of decoupling sequence will work best, for example, if the qubits are coupled to their environment through a purely dephasing interaction, a single-axis pulse sequence is effective in mitigating that interaction. If there are other terms in the interaction, multi-axis pulse sequences tend to perform better.
Keysight’s Quantum Control System offers a series of commonly used decoupling sequences that can be defined
through the total sequence length, number of pulses and/or the pulse interval. We
provide the DynamicalDecouplingExperiment
class
as an easy entrance point for testing out the sequences. The typical use case for
those sequences is to integrate them into a longer program (whenever certain qubits
are idle for a longer period of time), which we demonstrate at the end of this guide.
[2]:
import keysight.qcs as qcs
We start by initializing a qubit and defining an empty channel mapper to create a new
instance of the DynamicalDecouplingExperiment
class. We load a pre-defined CalibrationSet
that
contains a configuration for up to 10 qubits and linkers for the X
and Y
gates.
[3]:
from keysight.qcs.experiments import (
DynamicalDecouplingExperiment,
make_calibration_set,
)
from keysight.qcs.quantum import make_decoupling_sequence, SequenceType
n_qubits = 1
qubits = qcs.Qudits(range(n_qubits))
# generate an empty channel mapper
mapper = qcs.ChannelMapper("ip_addr")
# create a default calibration set for n_qubits
calibration_set = make_calibration_set(n_qubits)
# in its simplest form, this class generates a constant decoupling sequence with two
# pulses
dd_experiment = DynamicalDecouplingExperiment(
mapper,
calibration_set,
qubits,
total_duration=200e-9,
)
dd_experiment.program.draw()
dd_experiment.compiled_program.render()
Program
Program
|
||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||
|
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
This creates a program that contains two X
pulses and has a total duration of
200 ns. The finite pulse width is not taken into account by default, but can be
added by specifying the pulse_duration
argument, which will adjust the pulse
interval accordingly.
To customize the sequence, users can specify the following arguments:
total_duration
to set the total sequence duration
number_of_pulses
to set the number of pulses
pulse_interval
to specify the time between pulses
sequence_type
to specify which decoupling sequence should be used
Note that not all arguments are compatible with each other, e.g. specifying all three parameters for total duration, pulse number and pulse interval will result in an error.
Available dynamical decoupling sequences
The DynamicalDecouplingExperiment
supports the
following sequence types:
"DD"
: constant dynamical decoupling, implemented via the
constant_decoupling_sequence()
function,
"CPMG"
: the Carr-Purcell-Meiboom-Gill (CPMG) sequence, implemented via the
cpmg_sequence()
function,
"UHRIG"
: the Uhrig (or quadratic) sequence, implemented via the
uhrig_sequence()
function,
"XY4"
: the XY4 sequence, implemented via the
xy4_sequence()
function, and
"CDD"
: a concatenated decoupling sequence, implemented via the
concatenated_decoupling_sequence()
function that uses the XY4 sequence as a base sequence. Other base sequences can be specified when using this function directly.
These strings can be passed to the decoupling experiment to use other sequences. For example, the following creates a Uhrig decoupling sequence with 10 pulses:
[4]:
dd_experiment = DynamicalDecouplingExperiment(
mapper,
calibration_set,
qubits,
total_duration=200e-9,
number_of_pulses=10,
sequence_type=SequenceType.UHRIG,
)
dd_experiment.program.draw()
dd_experiment.compiled_program.render()
Program
Program
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
Integrating dynamical decoupling into another experiment
Dynamical decoupling can be used as an error suppression tool within other programs
and are typically integrated whenever there are long idle times for certain qubits.
Using the DynamicalDecouplingExperiment
class in
this use case is not practical, it is better to use the built-in functions for
creating single sequences as listed above, and then insert those into the program
layers directly.
For example, let’s consider the following program which has a two-qubit gates on qubits 1 and 2, leaving qubit 0 idle for a longer amount of time:
[5]:
qubits = qcs.Qudits(range(3))
prog = qcs.Program()
prog.add_gate(qcs.GATES.x, qubits[0])
prog.add_gate(qcs.GATES.h, qubits[1], new_layer=True)
prog.add_gate(qcs.GATES.cx, (qubits[1], qubits[2]))
prog.add_measurement(qubits)
prog.draw()
Program
Program
|
||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
Layer #1
Layer #1
|
Layer #2
Layer #2
|
Layer #3
Layer #3
|
|||||||||||||||||||||||
|
|
X
Gate X on ('qudits', 0)
Matrix:
|
Measure on ('qudits', 0)
Parameters
|
|||||||||||||||||||||||
|
H
Gate H on ('qudits', 1)
Matrix:
|
CX
Gate CX on (('qudits', 1), ('qudits', 2))
Matrix:
|
Measure on ('qudits', 1)
Parameters
|
|||||||||||||||||||||||
|
CX
Gate CX on (('qudits', 2), ('qudits', 1))
Matrix:
|
Measure on ('qudits', 2)
Parameters
|
We can insert a list of operations, e.g. a decoupling sequence into the second layer of the program. If the duration of the CX gate is known, we can use this to determine the decoupling sequence length.
[6]:
decoupling_duration = 150e-9
prog[2].insert(
qubits[0],
make_decoupling_sequence(
decoupling_duration, number_of_pulses=2, sequence_type=SequenceType.CPMG
),
)
prog.draw()
Program
Program
|
||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Layer #0
Layer #0
|
Layer #1
Layer #1
|
Layer #2
Layer #2
|
Layer #3
Layer #3
|
|||||||||||||||||||||||||||
|
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
X
Gate X on ('qudits', 0)
Matrix:
|
Delay on ('qudits', 0)
Parameters
|
Measure on ('qudits', 0)
Parameters
|
||||||||||||||||||||||
|
H
Gate H on ('qudits', 1)
Matrix:
|
CX
Gate CX on (('qudits', 1), ('qudits', 2))
Matrix:
|
Measure on ('qudits', 1)
Parameters
|
|||||||||||||||||||||||||||
|
CX
Gate CX on (('qudits', 2), ('qudits', 1))
Matrix:
|
Measure on ('qudits', 2)
Parameters
|
Download
Download this file as Jupyter notebook: qubit_dynamical_decoupling.ipynb.