Skip to content

Commit

Permalink
Merge pull request #832 from qiboteam/average
Browse files Browse the repository at this point in the history
Add average option to spectroscopy experiments
  • Loading branch information
andrea-pasquale authored May 22, 2024
2 parents e24d304 + 685e337 commit 7a422fc
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 157 deletions.
18 changes: 14 additions & 4 deletions doc/source/protocols/resonator_spectroscopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The bare resonator frequency can be found setting a large value for the amplitud
platform: <platform_name>
qubits: [0]
targets: [0]
actions:
Expand All @@ -44,6 +44,17 @@ The bare resonator frequency can be found setting a large value for the amplitud
nshots: 1024
relaxation_time: 100000
.. note::
The resonator spectroscopy experiment will be performed by computing
the average on hardware. If the user wants to retrieve all the shots
and perform the average afterwards it can be done by specifying the
entry `hardware_average: false` in the experiment parameters. In this
case the fitting procedure will take into account errors and error bands
will be included in the plot.

.. image:: resonator_spectroscopy_error_bars.png


.. image:: resonator_spectroscopy_high.png

Lowering the amplitude we can see a shift in the peak, e.g.:
Expand All @@ -52,7 +63,7 @@ Lowering the amplitude we can see a shift in the peak, e.g.:
platform: <platform_name>
qubits: [0]
targets: [0]
actions:
Expand Down Expand Up @@ -130,8 +141,7 @@ and also here:
single_qubit:
0:
bare_resonator_frequency: <high_power_resonator_frequency>
readout_frequency: 5_227_920_060
drive_frequency: <low_power_resonator_frequency>
readout_frequency: <low_power_resonator_frequency>
.. rubric:: References

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 21 additions & 20 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ classifiers = [
[tool.poetry.dependencies]
python = ">=3.9,<3.12"
qibolab = { git = "https://github.com/qiboteam/qibolab.git"}
qibo = "^0.2.7"
qibo ="^0.2.6"
numpy = "^1.26.4"
scipy = "^1.10.1"
pandas = "^1.4.3"
Expand All @@ -30,7 +30,7 @@ dash = "^2.6.0"
skops = "^0.6.0"
scikit-learn = "^1.2.1"
# Explicit dependency required to cope for dash: https://github.com/plotly/dash/issues/2557
setuptools = "^69.0.0"
setuptools = "^67.8.0"
matplotlib = { version = "^3.7.0", optional = true }
seaborn = { version = "^0.12.2", optional = true }
pydot = { version = "^1.4.2", optional = true }
Expand Down
26 changes: 25 additions & 1 deletion src/qibocal/auto/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import numpy as np
import numpy.typing as npt
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.qubits import Qubit, QubitId, QubitPair, QubitPairId

Expand Down Expand Up @@ -71,6 +72,10 @@ class Parameters:
"""Number of executions on hardware"""
relaxation_time: float
"""Wait time for the qubit to decohere back to the `gnd` state"""
hardware_average: bool = False
"""By default hardware average will be performed."""
classify: bool = False
"""By default qubit state classification will not be performed."""

@classmethod
def load(cls, input_parameters):
Expand All @@ -96,6 +101,24 @@ def load(cls, input_parameters):
setattr(instantiated_class, parameter, value)
return instantiated_class

@property
def execution_parameters(self):
"""Default execution parameters."""
averaging_mode = (
AveragingMode.CYCLIC if self.hardware_average else AveragingMode.SINGLESHOT
)
acquisition_type = (
AcquisitionType.DISCRIMINATION
if self.classify
else AcquisitionType.INTEGRATION
)
return ExecutionParameters(
nshots=self.nshots,
relaxation_time=self.relaxation_time,
acquisition_type=acquisition_type,
averaging_mode=averaging_mode,
)


class AbstractData:
"""Abstract data class."""
Expand Down Expand Up @@ -197,9 +220,10 @@ def register_qubit(self, dtype, data_keys, data_dict):
the values are the related arrays.
"""
# to be able to handle the non-sweeper case
ar = np.empty(np.shape(data_dict[list(data_dict.keys())[0]]), dtype=dtype)
ar = np.empty(np.shape(data_dict[list(data_dict)[0]]), dtype=dtype)
for key, value in data_dict.items():
ar[key] = value

if data_keys in self.data:
self.data[data_keys] = np.rec.array(
np.concatenate((self.data[data_keys], ar))
Expand Down
9 changes: 2 additions & 7 deletions src/qibocal/protocols/dispersive_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,14 @@ def _acquisition(

results_1 = platform.sweep(
sequence_1,
ExecutionParameters(
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.CYCLIC,
),
params.execution_parameters,
sweeper,
)

# retrieve the results for every qubit
for qubit in targets:
for i, results in enumerate([results_0, results_1]):
result = results[ro_pulses[qubit].serial]
result = results[ro_pulses[qubit].serial].average
# store the results
data.register_qubit(
DispersiveShiftType,
Expand Down
2 changes: 1 addition & 1 deletion src/qibocal/protocols/dispersive_shift_qutrit.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def _acquisition(
)

for qubit in targets:
result = results[qubit]
result = results[qubit].average
# store the results
data.register_qubit(
ResSpecType,
Expand Down
16 changes: 6 additions & 10 deletions src/qibocal/protocols/qubit_spectroscopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import Optional

import numpy as np
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId
Expand All @@ -27,6 +26,8 @@ class QubitSpectroscopyParameters(Parameters):
"""Drive pulse duration [ns]. Same for all qubits."""
drive_amplitude: Optional[float] = None
"""Drive pulse amplitude (optional). Same for all qubits."""
hardware_average: bool = True
"""By default hardware average will be performed."""


@dataclass
Expand Down Expand Up @@ -96,12 +97,7 @@ def _acquisition(

results = platform.sweep(
sequence,
ExecutionParameters(
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.SINGLESHOT,
),
params.execution_parameters,
sweeper,
)

Expand All @@ -113,11 +109,11 @@ def _acquisition(
ResSpecType,
(qubit),
dict(
signal=np.abs(result.average.voltage),
phase=np.mean(result.phase, axis=0),
signal=result.average.magnitude,
phase=result.average.phase,
freq=delta_frequency_range + qd_pulses[qubit].frequency,
error_signal=result.average.std,
error_phase=np.std(result.phase, axis=0, ddof=1),
error_phase=result.phase_std,
),
)
return data
Expand Down
67 changes: 40 additions & 27 deletions src/qibocal/protocols/qubit_spectroscopy_ef.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from dataclasses import asdict, dataclass, field

import numpy as np
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId
Expand Down Expand Up @@ -124,12 +123,7 @@ def _acquisition(

results = platform.sweep(
sequence,
ExecutionParameters(
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.SINGLESHOT,
),
params.execution_parameters,
sweeper,
)

Expand All @@ -141,11 +135,11 @@ def _acquisition(
ResSpecType,
(qubit),
dict(
signal=np.abs(result.average.voltage),
phase=np.mean(result.phase, axis=0),
signal=result.average.magnitude,
phase=result.average.phase,
freq=delta_frequency_range + qd_pulses[qubit].frequency,
error_signal=result.average.std,
error_phase=np.std(result.phase, axis=0, ddof=1),
error_phase=result.phase_std,
),
)
return data
Expand All @@ -156,25 +150,44 @@ def _plot(
):
"""Plotting function for QubitSpectroscopy."""
figures, report = spectroscopy_plot(data, target, fit)
show_error_bars = not np.isnan(data[target].error_signal).any()
if fit is not None:
report = table_html(
table_dict(
target,
[
"Frequency 1->2 [Hz]",
"Amplitude [a.u.]",
"Anharmonicity [Hz]",
"Chi2",
],
[
(fit.frequency[target], fit.error_fit_pars[target][1]),
(fit.amplitude[target], fit.error_fit_pars[target][0]),
(fit.anharmonicity[target], fit.error_fit_pars[target][2]),
fit.chi2_reduced[target],
],
display_error=True,
if show_error_bars:
report = table_html(
table_dict(
target,
[
"Frequency 1->2 [Hz]",
"Amplitude [a.u.]",
"Anharmonicity [Hz]",
"Chi2",
],
[
(fit.frequency[target], fit.error_fit_pars[target][1]),
(fit.amplitude[target], fit.error_fit_pars[target][0]),
(fit.anharmonicity[target], fit.error_fit_pars[target][2]),
fit.chi2_reduced[target],
],
display_error=True,
)
)
else:
report = table_html(
table_dict(
target,
[
"Frequency 1->2 [Hz]",
"Amplitude [a.u.]",
"Anharmonicity [Hz]",
],
[
fit.frequency[target],
fit.amplitude[target],
fit.anharmonicity[target],
],
display_error=False,
)
)
)

return figures, report

Expand Down
Loading

0 comments on commit 7a422fc

Please sign in to comment.