Download

Download this file as Jupyter notebook: program_basics.ipynb.

Program basics#

A Program contains a series of instructions to be performed on control hardware without requiring communication with the host computer.

Basic instructions and targets#

The set of allowed instructions for a Program includes abstract quantum operations such as single- or multi-qudit gates as well as hardware operations such as RF waveforms or digitizer instructions for acquisitions. While it is possible two combine both abstraction layers within a single program, for the purposes of this tutorial we will treat them separately.

The instruction targets in a Program can either be Channels or Qudits. The former is intended for use in waveform programs while the latter is intended for abstract quantum programs. See Linkers for more information for how to translate between these layers of abstraction.

The following program contains two Gaussian pulses on two abstract AWG channels and two acquisition readouts on two digitizer channels, with the first readout using a constant acquisition window and the second one using an integrated filter.

[2]:
import keysight.qcs as qcs

# define channels representing two AWGs and two digitizers
awgs = qcs.Channels(range(2), "awgs")
digs = qcs.Channels(range(2), "digs")

# instantiate an empty program
program = qcs.Program()

# instantiate a pulse with two different amplitudes
amps = qcs.Array("amplitudes", value=[1, 0.8])
freqs = qcs.Array("frequencies", value=[1.0e8, 5.1e8])
gauss = qcs.RFWaveform(8e-8, qcs.GaussianEnvelope(), amps, freqs)
readout = qcs.RFWaveform(8e-8, qcs.GaussianEnvelope(2), 0.5, 4.8e8)
# add the pulses to the program
program.add_waveform(gauss, awgs)

# add an acquisition to the program
program.add_acquisition(readout, digs[0])
program.add_acquisition(8e-8, digs[1])
program.add_acquisition(readout, digs[1], pre_delay=5e-9)
# visualize the program using the draw method:
program.draw()
Program
keysight-logo-svg
Program Body
Program
Duration 165 ns
Layers 1
Targets 4
Layer #0
Layer #0
Duration 165 ns
awgs 0
RFWaveform on ('awgs', 0)

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Amplitude Array(name=amplitudes, shape=(2,), dtype=float, unit=none, value=[1, 0.8])
Frequency Array(name=frequencies, shape=(2,), dtype=float, unit=Hz, value=[100 MHz, 510 MHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
1
RFWaveform on ('awgs', 1)

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Amplitude Array(name=amplitudes, shape=(2,), dtype=float, unit=none, value=[1, 0.8])
Frequency Array(name=frequencies, shape=(2,), dtype=float, unit=Hz, value=[100 MHz, 510 MHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
digs 0
Acquisition on ('digs', 0)

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Integration Filter
RFWaveform

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Amplitude 0.5
Frequency 480 MHz
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
1
Acquisition on ('digs', 1)

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Delay on ('digs', 1)

Parameters
Duration Scalar(name=_implicit, value=5 ns, dtype=float, unit=s)
Acquisition on ('digs', 1)

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Integration Filter
RFWaveform

Parameters
Duration Scalar(name=_implicit, value=80 ns, dtype=float, unit=s)
Amplitude 0.5
Frequency 480 MHz
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad

Hover over the operations in this visualization to view their specifications.

In this program, the first channel in awgs plays the pulse with amplitude 0.8 and the second channel plays the pulse with amplitude 1.0. Meanwhile, the first channel in digs rendered with a constant gate and the second channel in digs rendered with an integration filter, with amplitude 1.0 and 0.5, respectively. This can be verified by visualizing the pulses using the render() method.

[3]:
program.render(channel_subplots=False, sample_rate=5e9)

Timing model#

A Program consists of a series of Layers that represent instructions within a fixed time interval. When a program is constructed, new operations are added to the current layer if possible, otherwise a new Layer is created. The example below creates a program with the same instructions as before, but this time adds each to a new layer explicitly, causing them to be executed sequentially.

[4]:
program = qcs.Program()

# instantiate a pulse with two different amplitudes
gauss = qcs.RFWaveform(100e-9, qcs.GaussianEnvelope(), amps, freqs)

# add the pulses to the program using explicit indexing this time
program.add_waveform(gauss[0], awgs[0])

# create a new layer for the next pulse by setting new_layer=True
program.add_waveform(gauss[1], awgs[1], new_layer=True)

# add the acquisition
program.add_acquisition(100e-9, digs[0], new_layer=True)

program.draw()
Program
keysight-logo-svg
Program Body
Program
Duration 300 ns
Layers 3
Targets 3
Layer #0
Layer #0
Duration 100 ns
Layer #1
Layer #1
Duration 100 ns
Layer #2
Layer #2
Duration 100 ns
awgs 0
RFWaveform on ('awgs', 0)

Parameters
Duration Scalar(name=_implicit, value=100 ns, dtype=float, unit=s)
Amplitude ScalarRef(name=amplitudes, value=1, dtype=float, unit=none)
Frequency ScalarRef(name=frequencies, value=100 MHz, dtype=float, unit=Hz)
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
1
RFWaveform on ('awgs', 1)

Parameters
Duration Scalar(name=_implicit, value=100 ns, dtype=float, unit=s)
Amplitude ScalarRef(name=amplitudes, value=0.8, dtype=float, unit=none)
Frequency ScalarRef(name=frequencies, value=510 MHz, dtype=float, unit=Hz)
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
digs 0
Acquisition on ('digs', 0)

Parameters
Duration Scalar(name=_implicit, value=100 ns, dtype=float, unit=s)

The instructions are now in separate layers. The duration of each layer is determined by the maximum duration of each operation in that layer, or, if there are multiple operations in each layer, the maximum of the sum of operation durations.

Quantum Programs#

The Program class also supports circuit-level quantum programming where the targets are specified as Qudits and the operations are Gates. Multi-qudit targets can be created using tuples of single-qudit targets.

[5]:
qudits1 = qcs.Qudits(range(2), "xy_qudits")
qudits2 = qcs.Qudits(2, "other")

prog = qcs.Program()

prog.add_gate(qcs.GATES.x, qudits1[0])
prog.add_gate(qcs.GATES.cx, (qudits1[0], qudits2[0]))
prog.add_gate(qcs.GATES.y, qudits2, new_layer=True)

prog.add_gate(qcs.GATES.cx, (qudits1[1], qudits2[0]))

prog.add_measurement(qudits1[1], new_layer=True)
prog.add_measurement(qudits2, new_layer=True)

prog.add_gate(qcs.GATES.x, qudits1[0])

prog.draw()
Program
keysight-logo-svg
Program Body
Program
Duration undefined
Layers 6
Targets 3
Layer #0
Layer #0
Duration undefined
Layer #1
Layer #1
Duration undefined
Layer #2
Layer #2
Duration undefined
Layer #3
Layer #3
Duration undefined
Layer #4
Layer #4
Duration undefined
Layer #5
Layer #5
Duration undefined
xy_qudits 0
X
Gate X on ('xy_qudits', 0)

Matrix:
0 1
1 0
CX
Gate CX on (('xy_qudits', 0), ('other', 2))

Matrix:
1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0
X
Gate X on ('xy_qudits', 0)

Matrix:
0 1
1 0
1
CX
Gate CX on (('xy_qudits', 1), ('other', 2))

Matrix:
1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0
Measure on ('xy_qudits', 1)

Parameters
Dim 2
other 2
CX
Gate CX on (('other', 2), ('xy_qudits', 0))

Matrix:
1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0
Y
Gate Y on ('other', 2)

Matrix:
0 -1j
1j 0
CX
Gate CX on (('other', 2), ('xy_qudits', 1))

Matrix:
1 0 0 0
0 1 0 0
0 0 0 1
0 0 1 0
Measure on ('other', 2)

Parameters
Dim 2

The available built-in gates can be viewed through the aliases attribute:

[6]:
qcs.GATES.aliases
[6]:
{'cx', 'h', 'id', 'x', 'x90', 'y', 'y90', 'z', 'z90'}

Users can also specify their own gates with a matrix.


Download

Download this file as Jupyter notebook: program_basics.ipynb.