Download
Download this file as Jupyter notebook: simulated_experiment.ipynb.
Loading Simulated Experiment data
This section explains how to load simulated experiment data using the mock_data parameter. The mock_data parameter allows you to test and analyze experiments without requiring actual hardware execution.
The mock_data parameter should be structured as follows:
Keys: Instances of Channels representing the channels used in the experiment.
Values: Iterables containing the simulated data for each channel.
Example usage:
mock_data = {
channel_1: [trace_data_1, trace_data_2, ...],
channel_2: [trace_data_1, trace_data_2, ...],
qubit_1: [trace_data_1, trace_data_2, ...],
...
}
[2]:
import keysight.qcs as qcs
from keysight.qcs.experiments import Experiment, make_calibration_set
import numpy as np
Before creating the Experiment
with mock_data, we need a
ChannelMapper
and Program
object to tell the
Experiment
class for what data structure to expect for
mock_data.
Creating a dummy ChannelMapper
ChannelMapper
is required to configure the number of channels
available for acquisition, and how many number of channel-data to expect in mock_data.
The dimension of the accepted program is [n_shots, sweep_a, sweep_b, …, n_points]
n_shots: Number of program repetitions
sweep_a, sweep_b, …: Sweep variables
n_points: number of accepted points by the
IntegrationFilter
to covert trace data into IQ data.
[3]:
n_channels = 2
n_qubits = 2
n_points = 240 # points accepted by the integration filter
qubits = qcs.Qudits(range(n_qubits))
channels = qcs.Channels(range(n_channels), "xy_channels", absolute_phase=False)
mapper = qcs.ChannelMapper("dummy")
# assigning dummy physical addresses to the channels
for i in range(n_channels):
mapper.add_channel_mapping(
channels=channels[i],
addresses=qcs.Address(1, 1, i + 1),
instrument_types=qcs.InstrumentEnum.M5300AWG,
)
Loading a simple Sweep Program and Data
The Program
class gives information what dimension of data to expect
from mock_data. The program can be a simple non-iterating program, a normal sweep,
a nested sweep, or a zipped sweep. The data shape is determined by the structure of
program.repetitions.items.
Here, we will load data for a simple amplitude sweep program.
[4]:
n_shots = 7
num_amps = 13 # number of amplitude points to sweep on
program = qcs.Program()
amplitude = qcs.Scalar("amplitude", dtype=float)
phase = qcs.Scalar("phase", dtype=float)
amps = qcs.Array("amps", value=np.linspace(0, 0.8, num_amps), dtype=float)
waveform = qcs.RFWaveform(
duration=20e-9,
envelope=qcs.GaussianEnvelope(),
amplitude=amplitude,
rf_frequency=5.1e9,
)
program.add_waveform(waveform, channels)
int_filter = qcs.RFWaveform(10e-8, qcs.ConstantEnvelope(), 1, 5.15e9)
program.add_acquisition(int_filter, channels)
program.sweep(amps, amplitude).n_shots(n_shots)
# The shape of the accepted data must account for these dimensions
for i in program.repetitions.items:
print(i)
Repeat(7)
Sweep(amplitude=Array(name=amps, shape=(13,), dtype=float, unit=none))
Defining mock data and loading into the Experiment:
[5]:
hw_demod = False
# acceptable data shape
shape = [n_shots, num_amps, n_points]
# generate mock trace data
mock_data = dict()
for chan in channels:
mock_data[chan] = np.random.random(shape)
# load the mock_data using the mock_data parameter in the Experiment class
backend = qcs.HclBackend(mapper, hw_demod=hw_demod)
exp = Experiment(backend, make_calibration_set(2), qubits, program, mock_data=mock_data)
exp.get_iq() # or exp.get_trace()
[5]:
(((Channels(labels=[0], name=xy_channels, absolute_phase=False)))) | ... | (((Channels(labels=[1], name=xy_channels, absolute_phase=False)))) | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ... | 6 | |||||||||||||||||||
(amplitude, 0) | (amplitude, 0.0667) | (amplitude, 0.1333) | (amplitude, 0.2) | (amplitude, 0.2667) | (amplitude, 0.3333) | (amplitude, 0.4) | (amplitude, 0.4667) | (amplitude, 0.5333) | (amplitude, 0.6) | ... | (amplitude, 0.2) | (amplitude, 0.2667) | (amplitude, 0.3333) | (amplitude, 0.4) | (amplitude, 0.4667) | (amplitude, 0.5333) | (amplitude, 0.6) | (amplitude, 0.6667) | (amplitude, 0.7333) | (amplitude, 0.8) | |
0 | -0.042512+0.008492j | 0.014391+0.038994j | 0.021275-0.000037j | -0.031230-0.027157j | 0.019821+0.017045j | 0.040082+0.002105j | 0.016317-0.044579j | -0.023308-0.018232j | -0.012692-0.021363j | 0.023407+0.049343j | ... | 0.021203-0.028361j | 0.053482+0.001457j | -0.038046-0.002902j | 0.006084+0.015214j | -0.022269+0.004190j | -0.029753-0.010574j | 0.003708+0.039638j | -0.015368+0.020226j | 0.003973+0.017313j | -0.010057-0.013040j |
1 rows × 182 columns
Nested Sweeps with mock_data
Moving on to more complicated sweeps, we just have to that the shape of program.repetitions.items and our data matches.
[6]:
n_shots = 7
num_a = 13 # number of points to sweep on
num_b = 17 # number of points to sweep on
qubits = qcs.Qudits(range(n_qubits))
channels = qcs.Channels(range(n_channels), "xy_channels", absolute_phase=False)
program = qcs.Program()
amplitude = qcs.Scalar("amplitude", dtype=float)
phase = qcs.Scalar("phase", dtype=float)
amps = qcs.Array("amps", value=np.linspace(0, 0.8, num_a), dtype=float)
phases = qcs.Array("phases", value=np.linspace(0, np.pi, num_b), dtype=float)
waveform = qcs.RFWaveform(
duration=20e-9,
envelope=qcs.GaussianEnvelope(),
amplitude=amplitude,
rf_frequency=5.1e9,
instantaneous_phase=phase,
)
program.add_waveform(waveform, channels)
int_filter = qcs.RFWaveform(10e-8, qcs.ConstantEnvelope(), 1, 5.15e9)
program.add_acquisition(int_filter, channels)
program.sweep(amps, amplitude).sweep(phases, phase).n_shots(n_shots)
for i in program.repetitions.items:
print(i)
Repeat(7)
Sweep(phase=Array(name=phases, shape=(17,), dtype=float, unit=none))
Sweep(amplitude=Array(name=amps, shape=(13,), dtype=float, unit=none))
Defining and loading mock_data
[7]:
hw_demod = False
shape = [n_shots, num_a, num_b, n_points]
mock_data = dict()
for chan in channels:
mock_data[chan] = np.random.random(shape)
backend = qcs.HclBackend(mapper, hw_demod=hw_demod)
exp = Experiment(backend, make_calibration_set(2), qubits, program, mock_data=mock_data)
exp.get_iq() # OR exp.get_trace()
[7]:
(((Channels(labels=[0], name=xy_channels, absolute_phase=False)))) | ... | (((Channels(labels=[1], name=xy_channels, absolute_phase=False)))) | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ... | 6 | |||||||||||||||||||
(phase, 0 rad) | ... | (phase, 3.1415926536 rad) | |||||||||||||||||||
(amplitude, 0) | (amplitude, 0.0667) | (amplitude, 0.1333) | (amplitude, 0.2) | (amplitude, 0.2667) | (amplitude, 0.3333) | (amplitude, 0.4) | (amplitude, 0.4667) | (amplitude, 0.5333) | (amplitude, 0.6) | ... | (amplitude, 0.2) | (amplitude, 0.2667) | (amplitude, 0.3333) | (amplitude, 0.4) | (amplitude, 0.4667) | (amplitude, 0.5333) | (amplitude, 0.6) | (amplitude, 0.6667) | (amplitude, 0.7333) | (amplitude, 0.8) | |
0 | 0.026629-0.036679j | -0.012099-0.027187j | -0.000955+0.011343j | -0.062971+0.026197j | -0.015457+0.023539j | -0.015271+0.011937j | -0.025543+0.004013j | 0.051392-0.003721j | 0.020292+0.003681j | 0.010015+0.020205j | ... | -0.028832-0.001851j | 0.023153-0.005179j | 0.029179-0.006617j | 0.005455+0.010536j | 0.039557-0.004039j | -0.007190+0.019697j | -0.009913+0.005051j | -0.015347+0.011130j | -0.022465+0.012667j | 0.000136-0.009763j |
1 rows × 3094 columns
Zipped Sweeps with mock_data
Zipped sweeps have special structure in program.repetitions.items
[8]:
num_a = 13
# program
qubits = qcs.Qudits(range(n_channels))
channels = qcs.Channels(range(n_channels), "xy_channels", absolute_phase=False)
program = qcs.Program()
amplitude = qcs.Scalar("amplitude", dtype=float)
phase = qcs.Scalar("phase", dtype=float)
amps = qcs.Array("amps", value=np.linspace(0, 0.8, num_a), dtype=float)
phases = qcs.Array("phases", value=np.linspace(0, np.pi, num_a), dtype=float)
waveform = qcs.RFWaveform(
duration=20e-9,
envelope=qcs.GaussianEnvelope(),
amplitude=amplitude,
rf_frequency=5.1e9,
instantaneous_phase=phase,
)
program.add_waveform(waveform, channels)
int_filter = qcs.RFWaveform(10e-8, qcs.ConstantEnvelope(), 1, 5.15e9)
program.add_acquisition(int_filter, channels)
program.sweep((amps, phases), (amplitude, phase)).n_shots(n_shots)
for i in program.repetitions.items:
print(i)
Repeat(7)
Sweep(amplitude=Array(name=amps, shape=(13,), dtype=float, unit=none), phase=Array(name=phases, shape=(13,), dtype=float, unit=none))
Defining and loading mock_data
[9]:
# mock_data
shape = [n_shots, num_a, n_points]
mock_data = dict()
for chan in channels:
mock_data[chan] = np.random.random(shape)
# test for each mock_data
backend = qcs.HclBackend(mapper, hw_demod=hw_demod)
exp = Experiment(backend, make_calibration_set(2), qubits, program, mock_data=mock_data)
exp.get_iq() # OR exp.get_trace()
[9]:
(((Channels(labels=[0], name=xy_channels, absolute_phase=False)))) | ... | (((Channels(labels=[1], name=xy_channels, absolute_phase=False)))) | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | ... | 6 | |||||||||||||||||||
(amplitude, 0), (phase, 0 rad) | (amplitude, 0.0667), (phase, 261.8 mrad) | (amplitude, 0.1333), (phase, 523.6 mrad) | (amplitude, 0.2), (phase, 785.4 mrad) | (amplitude, 0.2667), (phase, 1.0471975512 rad) | (amplitude, 0.3333), (phase, 1.308996939 rad) | (amplitude, 0.4), (phase, 1.5707963268 rad) | (amplitude, 0.4667), (phase, 1.8325957146 rad) | (amplitude, 0.5333), (phase, 2.0943951024 rad) | (amplitude, 0.6), (phase, 2.3561944902 rad) | ... | (amplitude, 0.2), (phase, 785.4 mrad) | (amplitude, 0.2667), (phase, 1.0471975512 rad) | (amplitude, 0.3333), (phase, 1.308996939 rad) | (amplitude, 0.4), (phase, 1.5707963268 rad) | (amplitude, 0.4667), (phase, 1.8325957146 rad) | (amplitude, 0.5333), (phase, 2.0943951024 rad) | (amplitude, 0.6), (phase, 2.3561944902 rad) | (amplitude, 0.6667), (phase, 2.617993878 rad) | (amplitude, 0.7333), (phase, 2.8797932658 rad) | (amplitude, 0.8), (phase, 3.1415926536 rad) | |
0 | -0.014013-0.029417j | -0.001490+0.008065j | -0.024747+0.049757j | 0.004957-0.003326j | 0.013651-0.010994j | -0.029654-0.048599j | -0.015663+0.015767j | -0.011358-0.028260j | -0.000865+0.017295j | -0.044481-0.031627j | ... | -0.024265-0.019931j | -0.025587+0.013396j | 0.012244+0.011926j | 0.030737-0.027697j | 0.036103-0.015571j | -0.006798+0.038060j | -0.002361-0.023108j | 0.026858-0.020759j | -0.013224+0.035902j | 0.029077+0.002882j |
1 rows × 182 columns
Example for a Qubit level program
For qubit level program, the user need to additionally take care of the calibration set and the application of LinkerPass to the program, as shown below:
[10]:
# channel mapper
n_channels = 2
n_qubits = 2
n_points = 240 # points accepted by the integration filter
mapper = qcs.ChannelMapper("dummy")
# channel_acq required for qubit-type mock_data
# our default function qcs.experiments.make_calibration_set` creates channels with
# name="readout_acquisition", and supporting linkers for it.
channels_acq = qcs.Channels(
range(n_channels), "readout_acquisition", absolute_phase=True
)
# assigning dummy physical addresses to the channels
for i in range(n_channels):
mapper.add_channel_mapping(
channels=channels_acq[i],
addresses=qcs.Address(2, 1, i + 1),
instrument_types=qcs.InstrumentEnum.M5300AWG,
)
Defining the program and other components:
[11]:
n_shots = 7
num_amps = 13 # number of amplitude points to sweep on
hw_demod = False
qubits = qcs.Qudits(range(n_channels))
channels_acq = qcs.Channels(
range(n_channels), "readout_acquisition", absolute_phase=True
)
program = qcs.Program()
program.add_measurement(qubits)
program.n_shots(n_shots)
# Additional steps: Defining the calibration set and applying LinkerPass
cal_set = make_calibration_set(n_channels)
program = qcs.LinkerPass(*cal_set.linkers.values()).apply(program)
# mock_data for qubits
mock_data = dict()
for qub in qubits:
mock_data[qub] = np.random.random((n_shots, n_points))
backend = qcs.HclBackend(mapper, hw_demod=hw_demod)
exp = Experiment(backend, make_calibration_set(2), qubits, program, mock_data=mock_data)
exp.get_iq()
[11]:
(((Qudits(labels=[0], name=qudits, dim=2)))) | (((Qudits(labels=[1], name=qudits, dim=2)))) | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
0 | 0.034408+0.026937j | -0.011381+0.056264j | 0.026001+0.050744j | 0.032002-0.039275j | 0.052135-0.026205j | -0.016844-0.017455j | 0.027700+0.015079j | 0.003168-0.001767j | -0.023733-0.037413j | 0.000239+0.021390j | 0.008638-0.018321j | 0.022567-0.020590j | -0.011178-0.015789j | -0.015632+0.045966j |
Download
Download this file as Jupyter notebook: simulated_experiment.ipynb.