From cd181a28a68084b26e2ed3ed2fff9d1c0eefa500 Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 15 Nov 2023 21:08:16 +0400 Subject: [PATCH 01/13] Add virtual z routine with probabilities (no errors) --- .../protocols/characterization/__init__.py | 9 ++++++++- .../two_qubit_interaction/__init__.py | 2 ++ .../two_qubit_interaction/cz_virtualz.py | 16 +++++++++------- tests/runcards/protocols.yml | 12 ++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/qibocal/protocols/characterization/__init__.py b/src/qibocal/protocols/characterization/__init__.py index b22fc7737..479b11b9b 100644 --- a/src/qibocal/protocols/characterization/__init__.py +++ b/src/qibocal/protocols/characterization/__init__.py @@ -51,7 +51,13 @@ from .resonator_spectroscopy import resonator_spectroscopy from .resonator_spectroscopy_attenuation import resonator_spectroscopy_attenuation from .signal_experiments.time_of_flight_readout import time_of_flight_readout -from .two_qubit_interaction import chevron, chsh_circuits, chsh_pulses, cz_virtualz +from .two_qubit_interaction import ( + chevron, + chsh_circuits, + chsh_pulses, + cz_virtualz, + cz_virtualz_signal, +) class Operation(Enum): @@ -110,3 +116,4 @@ class Operation(Enum): dispersive_shift_qutrit = dispersive_shift_qutrit coupler_resonator_spectroscopy = coupler_resonator_spectroscopy coupler_qubit_spectroscopy = coupler_qubit_spectroscopy + cz_virtualz_signal = cz_virtualz_signal diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py index 5b247bf04..233c25676 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py @@ -1,3 +1,5 @@ from .chevron import chevron from .chsh import chsh_circuits, chsh_pulses from .cz_virtualz import cz_virtualz +from .cz_virtualz_signal import cz_virtualz_signal +from .tune_landscape import tune_landscape diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index 76dc4499f..edf713072 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -209,14 +209,14 @@ def _acquisition( sequence, ExecutionParameters( nshots=params.nshots, - acquisition_type=AcquisitionType.INTEGRATION, + acquisition_type=AcquisitionType.DISCRIMINATION, averaging_mode=AveragingMode.CYCLIC, ), sweeper, ) - result_target = results[target_q].magnitude - result_control = results[control_q].magnitude + result_target = results[target_q].probability(0) + result_control = results[control_q].probability(0) data.register_qubit( CZVirtualZType, @@ -259,14 +259,16 @@ def _fit( np.mean(target_data), 3.14, ] - try: popt, _ = curve_fit( fit_function, np.array(data.thetas) + data.vphases[pair][target], target_data, p0=pguess, - bounds=((0, 0, 0), (2.5, 2.5, 2 * np.pi)), + bounds=( + (-np.max(target_data), -np.max(target_data), 0), + (np.max(target_data), np.max(target_data), 2 * np.pi), + ), ) fitted_parameters[target, control, setup] = popt.tolist() @@ -378,7 +380,7 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): uirevision="0", # ``uirevision`` allows zooming while live plotting xaxis1_title="theta [rad] + virtual phase[rad]", xaxis2_title="theta [rad] + virtual phase [rad]", - yaxis_title="Signal [a.u.]", + yaxis_title="Probability of State 0", ) fig2.update_layout( @@ -387,7 +389,7 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): uirevision="0", # ``uirevision`` allows zooming while live plotting xaxis1_title="theta [rad] + virtual phase[rad]", xaxis2_title="theta [rad] + virtual phase[rad]", - yaxis_title="Signal [a.u.]", + yaxis_title="Probability of State 0", ) return [fig1, fig2], fitting_report diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index 9cde41d4b..c100c345f 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -547,6 +547,18 @@ actions: dt: 0 parking: True + - id: tune landscape signal + priority: 0 + operation: cz_virtualz_signal + qubits: [[0, 2],[1,2],[3,2]] + parameters: + theta_start: 0 + theta_end: 180 + theta_step: 10 + flux_pulse_amplitude: 0.5 + dt: 0 + parking: True + - id: standard rb inhomogeneous priority: 0 operation: standard_rb From aa8f91e527d9b56c449c3cc6c1899236d54cbbf3 Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 15 Nov 2023 21:13:22 +0400 Subject: [PATCH 02/13] Add missing file --- .../two_qubit_interaction/__init__.py | 1 - .../cz_virtualz_signal.py | 139 ++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py index 233c25676..e9f98127d 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py @@ -2,4 +2,3 @@ from .chsh import chsh_circuits, chsh_pulses from .cz_virtualz import cz_virtualz from .cz_virtualz_signal import cz_virtualz_signal -from .tune_landscape import tune_landscape diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py new file mode 100644 index 000000000..7c204cd05 --- /dev/null +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py @@ -0,0 +1,139 @@ +"""CZ virtual correction experiment for two qubit gates, tune landscape.""" +from dataclasses import dataclass + +import numpy as np +from qibolab import AcquisitionType, AveragingMode, ExecutionParameters +from qibolab.platform import Platform +from qibolab.sweeper import Parameter, Sweeper, SweeperType + +from qibocal.auto.operation import QubitsPairs, Routine +from qibocal.protocols.characterization.two_qubit_interaction.chevron import order_pair + +from .cz_virtualz import ( + CZVirtualZData, + CZVirtualZParameters, + CZVirtualZResults, + CZVirtualZType, + _fit, +) +from .cz_virtualz import _plot as _plot_prob +from .cz_virtualz import _update, create_sequence + + +@dataclass +class CZVirtualZSignalParameters(CZVirtualZParameters): + """CzVirtualZ runcard inputs.""" + + +@dataclass +class CZVirtualZSignalResults(CZVirtualZResults): + """CzVirtualZ outputs when fitting will be done.""" + + +CZVirtualZType = np.dtype([("target", np.float64), ("control", np.float64)]) + + +@dataclass +class CZVirtualZSignalData(CZVirtualZData): + """CZVirtualZ data.""" + + +def _acquisition( + params: CZVirtualZSignalParameters, + platform: Platform, + qubits: QubitsPairs, +) -> CZVirtualZSignalData: + r""" + Acquisition for CZVirtualZ. + + Check the two-qubit landscape created by a flux pulse of a given duration + and amplitude. + The system is initialized with a Y90 pulse on the low frequency qubit and either + an Id or an X gate on the high frequency qubit. Then the flux pulse is applied to + the high frequency qubit in order to perform a two-qubit interaction. The Id/X gate + is undone in the high frequency qubit and a theta90 pulse is applied to the low + frequency qubit before measurement. That is, a pi-half pulse around the relative phase + parametereized by the angle theta. + Measurements on the low frequency qubit yield the 2Q-phase of the gate and the + remnant single qubit Z phase aquired during the execution to be corrected. + Population of the high frequency qubit yield the leakage to the non-computational states + during the execution of the flux pulse. + """ + + theta_absolute = np.arange(params.theta_start, params.theta_end, params.theta_step) + data = CZVirtualZData(thetas=theta_absolute.tolist()) + for pair in qubits: + # order the qubits so that the low frequency one is the first + ord_pair = order_pair(pair, platform.qubits) + + for target_q, control_q in ( + (ord_pair[0], ord_pair[1]), + (ord_pair[1], ord_pair[0]), + ): + for setup in ("I", "X"): + ( + sequence, + virtual_z_phase, + theta_pulse, + data.amplitudes[ord_pair], + ) = create_sequence( + platform, + setup, + target_q, + control_q, + ord_pair, + params.dt, + params.parking, + params.flux_pulse_amplitude, + ) + data.vphases[ord_pair] = dict(virtual_z_phase) + theta = np.arange( + virtual_z_phase[target_q] + params.theta_start, + virtual_z_phase[target_q] + params.theta_end, + params.theta_step, + dtype=float, + ) + sweeper = Sweeper( + Parameter.relative_phase, + theta, + pulses=[theta_pulse], + type=SweeperType.ABSOLUTE, + ) + results = platform.sweep( + sequence, + ExecutionParameters( + nshots=params.nshots, + acquisition_type=AcquisitionType.INTEGRATION, + averaging_mode=AveragingMode.CYCLIC, + ), + sweeper, + ) + + result_target = results[target_q].magnitude + result_control = results[control_q].magnitude + + data.register_qubit( + CZVirtualZType, + (target_q, control_q, setup), + dict( + target=result_target, + control=result_control, + ), + ) + return data + + +def _plot(data: CZVirtualZSignalData, fit: CZVirtualZSignalResults, qubit): + """Plot routine for CZVirtualZ.""" + figs, fitting_report = _plot_prob(data, fit, qubit) + + for fig in figs: + fig.update_layout( + yaxis_title="Signal [a.u.]", + ) + + return figs, fitting_report + + +cz_virtualz_signal = Routine(_acquisition, _fit, _plot, _update, two_qubit_gates=True) +"""CZ virtual Z correction routine.""" From c56f2dd971602d2a1c09a9781042656dce4eaded Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 15 Nov 2023 22:17:39 +0400 Subject: [PATCH 03/13] Add proper leakage --- .../two_qubit_interaction/chevron.py | 2 +- .../two_qubit_interaction/cz_virtualz.py | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py b/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py index f75e96c45..dd17d998e 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py @@ -298,7 +298,7 @@ def _plot(data: ChevronData, fit: ChevronResults, qubit): fig.update_layout( xaxis_title="Duration [ns]", xaxis2_title="Duration [ns]", - yaxis_title="Amplitude [dimensionless]", + yaxis_title="Amplitude [a.u.]", legend=dict(orientation="h"), ) fig.update_layout( diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index edf713072..87d2ac02c 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -48,6 +48,8 @@ class CZVirtualZResults(Results): """CZ angle.""" virtual_phase: dict[QubitPairId, dict[QubitId, float]] """Virtual Z phase correction.""" + leakage: dict[QubitPairId, dict[QubitId, float]] + """Leakage on control qubit for pair.""" CZVirtualZType = np.dtype([("target", np.float64), ("control", np.float64)]) @@ -215,8 +217,8 @@ def _acquisition( sweeper, ) - result_target = results[target_q].probability(0) - result_control = results[control_q].probability(0) + result_target = results[target_q].probability(1) + result_control = results[control_q].probability(1) data.register_qubit( CZVirtualZType, @@ -250,8 +252,10 @@ def _fit( pairs = data.pairs virtual_phase = {} cz_angle = {} + leakage = {} for pair in pairs: virtual_phase[pair] = {} + leakage[pair] = {} for target, control, setup in data[pair]: target_data = data[pair][target, control, setup].target pguess = [ @@ -284,14 +288,24 @@ def _fit( fitted_parameters[target_q, control_q, "X"][2] - fitted_parameters[target_q, control_q, "I"][2] ) - virtual_phase[pair][target_q] = -fitted_parameters[ - target_q, control_q, "I" - ][2] + virtual_phase[pair][target_q] = fitted_parameters[target_q, control_q, "I"][ + 2 + ] + # leakage estimate: L = m /2 + # See NZ paper from Di Carlo + # approximation which does not need qutrits + leakage[pair][control_q] = 0.5 * float( + np.mean( + data[pair][target_q, control_q, "X"].control + - data[pair][target_q, control_q, "I"].control + ) + ) return CZVirtualZResults( cz_angle=cz_angle, virtual_phase=virtual_phase, fitted_parameters=fitted_parameters, + leakage=leakage, ) @@ -364,12 +378,13 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): fitting_report = table_html( table_dict( - [target, target, qubits[1]], - ["CZ angle", "Virtual Z phase", "Flux pulse amplitude"], + [target, target, qubits[1], control], + ["CZ angle", "Virtual Z phase", "Flux pulse amplitude", "Leakage"], [ np.round(fit.cz_angle[target, control], 4), np.round(fit.virtual_phase[tuple(sorted(qubit))][target], 4), np.round(data.amplitudes[qubits]), + np.round(fit.leakage[tuple(sorted(qubit))][control], 4), ], ) ) @@ -398,7 +413,8 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): def _update(results: CZVirtualZResults, platform: Platform, qubit_pair: QubitPairId): # FIXME: quick fix for qubit order qubit_pair = tuple(sorted(qubit_pair)) - update.virtual_phases(results.virtual_phase[qubit_pair], platform, qubit_pair) + # FIXME: the virtual phase should be corrected with a negative sign? + update.virtual_phases(-results.virtual_phase[qubit_pair], platform, qubit_pair) cz_virtualz = Routine(_acquisition, _fit, _plot, _update, two_qubit_gates=True) From 1e2d20f72176abeb53d906e487edc426524c5126 Mon Sep 17 00:00:00 2001 From: Andrea Date: Wed, 15 Nov 2023 22:26:27 +0400 Subject: [PATCH 04/13] Add duration to cz protocols --- .../two_qubit_interaction/cz_virtualz.py | 28 ++++++++++++++++--- .../cz_virtualz_signal.py | 1 + tests/runcards/protocols.yml | 2 ++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index 87d2ac02c..ab3b5a2e2 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -32,6 +32,8 @@ class CZVirtualZParameters(Parameters): """Step size for the theta sweep in radians.""" flux_pulse_amplitude: Optional[float] = None """Amplitude of flux pulse implementing CZ.""" + flux_pulse_duration: Optional[float] = None + """Duration of flux pulse implementing CZ.""" dt: Optional[float] = 20 """Time delay between flux pulses and readout.""" parking: bool = True @@ -63,6 +65,7 @@ class CZVirtualZData(Data): thetas: list = field(default_factory=list) vphases: dict[QubitPairId, dict[QubitId, float]] = field(default_factory=dict) amplitudes: dict[tuple[QubitId, QubitId], float] = field(default_factory=dict) + durations: dict[tuple[QubitId, QubitId], float] = field(default_factory=dict) def __getitem__(self, pair): return { @@ -81,8 +84,13 @@ def create_sequence( parking: bool, dt: float, amplitude: float = None, + duration: float = None, ) -> tuple[ - PulseSequence, dict[QubitId, Pulse], dict[QubitId, Pulse], dict[QubitId, Pulse] + PulseSequence, + dict[QubitId, Pulse], + dict[QubitId, Pulse], + dict[QubitId, Pulse], + dict[QubitId, Pulse], ]: """Create the experiment PulseSequence.""" @@ -101,6 +109,9 @@ def create_sequence( if amplitude is not None: cz.get_qubit_pulses(ordered_pair[1])[0].amplitude = amplitude + if duration is not None: + cz.get_qubit_pulses(ordered_pair[1])[0].duration = duration + theta_pulse = platform.create_RX90_pulse( target_qubit, start=cz.finish + dt, @@ -143,6 +154,7 @@ def create_sequence( virtual_z_phase, theta_pulse, cz.get_qubit_pulses(ordered_pair[1])[0].amplitude, + cz.get_qubit_pulses(ordered_pair[1])[0].duration, ) @@ -184,6 +196,7 @@ def _acquisition( virtual_z_phase, theta_pulse, data.amplitudes[ord_pair], + data.durations[ord_pair], ) = create_sequence( platform, setup, @@ -378,12 +391,19 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): fitting_report = table_html( table_dict( - [target, target, qubits[1], control], - ["CZ angle", "Virtual Z phase", "Flux pulse amplitude", "Leakage"], + [target, target, qubits[1], qubit[1], control], + [ + "CZ angle", + "Virtual Z phase", + "Flux pulse amplitude", + "Flux pulse duration", + "Leakage", + ], [ np.round(fit.cz_angle[target, control], 4), np.round(fit.virtual_phase[tuple(sorted(qubit))][target], 4), np.round(data.amplitudes[qubits]), + np.round(data.durations[qubits]), np.round(fit.leakage[tuple(sorted(qubit))][control], 4), ], ) @@ -414,7 +434,7 @@ def _update(results: CZVirtualZResults, platform: Platform, qubit_pair: QubitPai # FIXME: quick fix for qubit order qubit_pair = tuple(sorted(qubit_pair)) # FIXME: the virtual phase should be corrected with a negative sign? - update.virtual_phases(-results.virtual_phase[qubit_pair], platform, qubit_pair) + update.virtual_phases(results.virtual_phase[qubit_pair], platform, qubit_pair) cz_virtualz = Routine(_acquisition, _fit, _plot, _update, two_qubit_gates=True) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py index 7c204cd05..6a5e0edcd 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py @@ -76,6 +76,7 @@ def _acquisition( virtual_z_phase, theta_pulse, data.amplitudes[ord_pair], + data.durations[ord_pair], ) = create_sequence( platform, setup, diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index c100c345f..46eb71e7b 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -544,6 +544,7 @@ actions: theta_end: 180 theta_step: 10 flux_pulse_amplitude: 0.5 + flux_pulse_duration: 10 dt: 0 parking: True @@ -556,6 +557,7 @@ actions: theta_end: 180 theta_step: 10 flux_pulse_amplitude: 0.5 + flux_pulse_duration: 10 dt: 0 parking: True From 8fd845d9ac8efe69ce9c331d3f2bb278e9353ba5 Mon Sep 17 00:00:00 2001 From: Andrea Date: Mon, 20 Nov 2023 15:38:59 +0100 Subject: [PATCH 05/13] Add tune landscape over amplitude and duration with for loops --- .../protocols/characterization/__init__.py | 2 + .../two_qubit_interaction/__init__.py | 1 + .../two_qubit_interaction/cz_virtualz.py | 2 - .../two_qubit_interaction/tune_landscape.py | 226 ++++++++++++++++++ tests/runcards/protocols.yml | 29 ++- 5 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py diff --git a/src/qibocal/protocols/characterization/__init__.py b/src/qibocal/protocols/characterization/__init__.py index 479b11b9b..763bf499e 100644 --- a/src/qibocal/protocols/characterization/__init__.py +++ b/src/qibocal/protocols/characterization/__init__.py @@ -57,6 +57,7 @@ chsh_pulses, cz_virtualz, cz_virtualz_signal, + tune_landscape, ) @@ -117,3 +118,4 @@ class Operation(Enum): coupler_resonator_spectroscopy = coupler_resonator_spectroscopy coupler_qubit_spectroscopy = coupler_qubit_spectroscopy cz_virtualz_signal = cz_virtualz_signal + tune_landscape = tune_landscape diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py index e9f98127d..233c25676 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py @@ -2,3 +2,4 @@ from .chsh import chsh_circuits, chsh_pulses from .cz_virtualz import cz_virtualz from .cz_virtualz_signal import cz_virtualz_signal +from .tune_landscape import tune_landscape diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index ab3b5a2e2..5df7232e0 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -412,7 +412,6 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): fig1.update_layout( title_text=f"Phase correction Qubit {qubits[0]}", showlegend=True, - uirevision="0", # ``uirevision`` allows zooming while live plotting xaxis1_title="theta [rad] + virtual phase[rad]", xaxis2_title="theta [rad] + virtual phase [rad]", yaxis_title="Probability of State 0", @@ -421,7 +420,6 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, qubit): fig2.update_layout( title_text=f"Phase correction Qubit {qubits[1]}", showlegend=True, - uirevision="0", # ``uirevision`` allows zooming while live plotting xaxis1_title="theta [rad] + virtual phase[rad]", xaxis2_title="theta [rad] + virtual phase[rad]", yaxis_title="Probability of State 0", diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py new file mode 100644 index 000000000..6151a5987 --- /dev/null +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py @@ -0,0 +1,226 @@ +"""CZ virtual correction experiment for two qubit gates, tune landscape.""" +from dataclasses import dataclass, field +from typing import Optional + +import numpy as np +import numpy.typing as npt +import plotly.graph_objects as go +from plotly.subplots import make_subplots +from qibolab.platform import Platform + +from qibocal.auto.operation import Data, Parameters, QubitsPairs, Results, Routine + +from .cz_virtualz import cz_virtualz + +COLORAXIS = ["coloraxis2", "coloraxis1"] + + +@dataclass +class TuneLandscapeParameters(Parameters): + """CzVirtualZ runcard inputs.""" + + amplitude_min: float + """Amplitude minimum.""" + amplitude_max: float + """Amplitude maximum.""" + amplitude_step: float + """Amplitude step.""" + duration_min: float + """Duration minimum.""" + duration_max: float + """Duration maximum.""" + duration_step: float + """Duration step.""" + dt: Optional[float] = 20 + """Time delay between flux pulses and readout.""" + parking: bool = True + """Wether to park non interacting qubits or not.""" + + +@dataclass +class TuneLandscapeResults(Results): + """CzVirtualZ outputs when fitting will be done.""" + + +TuneLandscapeType = np.dtype( + [ + ("leakage", np.float64), + ("cz_angle", np.float64), + ("phase", np.float64), + ("length", np.float64), + ("amp", np.float64), + ] +) + + +@dataclass +class TuneLandscapeData(Data): + """CZVirtualZ data.""" + + data: dict[tuple, npt.NDArray[TuneLandscapeType]] = field(default_factory=dict) + + def __getitem__(self, pair): + return { + index: value + for index, value in self.data.items() + if set(pair).issubset(index) + } + + def register_qubit( + self, target_q, control_q, duration, amplitude, leakage, cz_angle, phase + ): + """Store output for single qubit.""" + ar = np.empty((1,), dtype=TuneLandscapeType) + ar["length"] = duration + ar["amp"] = amplitude + ar["leakage"] = leakage + ar["cz_angle"] = cz_angle + ar["phase"] = phase + + if (target_q, control_q) in self.data: + self.data[target_q, control_q] = np.rec.array( + np.concatenate((self.data[target_q, control_q], ar)) + ) + else: + self.data[target_q, control_q] = np.rec.array(ar) + + +# TODO: make acquisition working regardless of the qubits order +def _acquisition( + params: TuneLandscapeParameters, + platform: Platform, + qubits: QubitsPairs, +) -> TuneLandscapeData: + r""" + Acquisition for tune landscape. + + Currently this experiments perform the CZVirtualZ protocols for different + amplitudes and durations of the flux pulse. The leakage and the CZ angle are + plotted for each configuration. + """ + + data = TuneLandscapeData() + amplitude_range = np.arange( + params.amplitude_min, + params.amplitude_max, + params.amplitude_step, + ) + + duration_range = np.arange( + params.duration_min, params.duration_max, params.duration_step + ) + + for amplitude in amplitude_range: + for duration in duration_range: + cz_data, _ = cz_virtualz.acquisition( + params=cz_virtualz.parameters_type.load( + dict( + theta_start=0, + theta_end=7, + theta_step=0.1, + flux_pulse_amplitude=amplitude, + flux_pulse_duration=duration, + ) + ), + platform=platform, + qubits=qubits, + ) + cz_fit, _ = cz_virtualz.fit(cz_data) + + for pair in qubits: + for target_q, control_q in ( + pair, + list(pair)[::-1], + ): + data.register_qubit( + target_q, + control_q, + duration, + amplitude, + leakage=cz_fit.leakage[pair][control_q], + cz_angle=cz_fit.cz_angle[pair], + phase=cz_fit.virtual_phase[pair][target_q], + ) + + return data + + +def _fit( + data: TuneLandscapeData, +) -> TuneLandscapeResults: + return TuneLandscapeResults() + + +def _plot(data: TuneLandscapeData, fit: TuneLandscapeResults, qubit): + pair_data = data[qubit] + qubits = next(iter(pair_data))[:2] + fig1 = make_subplots( + rows=1, + cols=2, + subplot_titles=( + f"Leakage Qubit {qubits[0]}", + f"Leakage Qubit {qubits[1]}", + ), + ) + fig2 = make_subplots( + rows=1, + cols=2, + subplot_titles=( + f"CZ angle Qubit {qubits[0]}", + f"CZ angle Qubit {qubits[1]}", + ), + ) + + for target, control in pair_data: + fig1.add_trace( + go.Heatmap( + x=pair_data[target, control].length, + y=pair_data[target, control].amp, + z=abs( + pair_data[target, control].leakage + ), # TODO: check if you need abs + name=f"Leakage qubit {target}", + colorbar=dict( + tickmode="array", + tickvals=[0, 0.1, 0.2, 0.3, 0.4], + ticktext=["0", "0.1", "0.2", "0.3", "0.4"], # Set the tick labels + ), + ), + row=1, + col=1 if (target, control) == qubits else 2, + ) + + fig2.add_trace( + go.Heatmap( + x=pair_data[target, control].length, + y=pair_data[target, control].amp, + z=pair_data[target, control].cz_angle, + colorscale="RdBu", + colorbar=dict( + tickmode="array", + tickvals=[0, np.pi / 2, np.pi, 3 * np.pi / 2, 2 * np.pi], + ticktext=[ + "0", + "1.57", + "3.14", + "4.71", + "6.28", + ], # Set the tick labels + ), + name=f"CZ angle [rad] qubit {target}", + ), + row=1, + col=1 if (target, control) == qubits else 2, + ) + + return [fig1, fig2], "" + + +# def _update(results: CZVirtualZResults, platform: Platform, qubit_pair: QubitPairId): +# # FIXME: quick fix for qubit order +# qubit_pair = tuple(sorted(qubit_pair)) +# update.virtual_phases(results.virtual_phase[qubit_pair], platform, qubit_pair) + + +tune_landscape = Routine(_acquisition, _fit, _plot, two_qubit_gates=True) +"""CZ virtual Z correction routine.""" diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index 46eb71e7b..c60f7effc 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -535,7 +535,7 @@ actions: nshots: 1000 parking: True - - id: tune landscape + - id: cz priority: 0 operation: cz_virtualz qubits: [[0, 2],[1,2],[3,2]] @@ -548,6 +548,19 @@ actions: dt: 0 parking: True + - id: cz signal + priority: 0 + operation: cz_virtualz_signal + qubits: [[0, 2],[1,2],[3,2]] + parameters: + theta_start: 0 + theta_end: 180 + theta_step: 10 + flux_pulse_amplitude: 0.5 + flux_pulse_duration: 10 + dt: 0 + parking: True + - id: tune landscape signal priority: 0 operation: cz_virtualz_signal @@ -561,6 +574,20 @@ actions: dt: 0 parking: True + + - id: tune landscape + priority: 0 + operation: tune_landscape + qubits: [[0, 2],[1,2],[2,3]] + parameters: + amplitude_min: 0.1 + amplitude_max: 0.2 + amplitude_step: 0.01 + duration_min: 10 + duration_max: 20 + duration_step: 1 + + - id: standard rb inhomogeneous priority: 0 operation: standard_rb From 4266954d989b354934b1cd9364c65de4ee4ea593 Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Wed, 27 Mar 2024 18:24:45 +0400 Subject: [PATCH 06/13] feat: Relative amplitude in Chevron --- .../two_qubit_interaction/chevron.py | 37 ++++++++++++++----- .../two_qubit_interaction/cz_virtualz.py | 4 +- tests/runcards/protocols.yml | 6 +-- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py b/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py index 75f0507c1..26bc952f4 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/chevron.py @@ -27,11 +27,11 @@ class ChevronParameters(Parameters): """CzFluxTime runcard inputs.""" - amplitude_min: float + amplitude_min_factor: float """Amplitude minimum.""" - amplitude_max: float + amplitude_max_factor: float """Amplitude maximum.""" - amplitude_step: float + amplitude_step_factor: float """Amplitude step.""" duration_min: float """Duration minimum.""" @@ -54,6 +54,9 @@ class ChevronResults(Results): duration: dict[QubitPairId, int] """Virtual Z phase correction.""" + def __contains__(self, key: QubitPairId): + return super().__contains__(key) | super().__contains__((key[1], key[0])) + ChevronType = np.dtype( [ @@ -70,6 +73,10 @@ class ChevronResults(Results): class ChevronData(Data): """Chevron acquisition outputs.""" + cz_amplitude: dict[QubitPairId, float] = field(default_factory=dict) + """CZ platform amplitude for qubit pair.""" + sweetspot: dict[QubitPairId, float] = field(default_factory=dict) + """Sweetspot value for high frequency qubit.""" data: dict[QubitPairId, npt.NDArray[ChevronType]] = field(default_factory=dict) def register_qubit(self, low_qubit, high_qubit, length, amp, prob_low, prob_high): @@ -106,6 +113,7 @@ def _aquisition( for pair in targets: # order the qubits so that the low frequency one is the first sequence = PulseSequence() + ordered_pair = order_pair(pair, platform) # initialize in system in 11 state initialize_lowfreq = platform.create_RX_pulse( @@ -152,9 +160,9 @@ def _aquisition( # define the parameter to sweep and its range: delta_amplitude_range = np.arange( - params.amplitude_min, - params.amplitude_max, - params.amplitude_step, + params.amplitude_min_factor, + params.amplitude_max_factor, + params.amplitude_step_factor, ) delta_duration_range = np.arange( params.duration_min, params.duration_max, params.duration_step @@ -164,8 +172,13 @@ def _aquisition( Parameter.amplitude, delta_amplitude_range, pulses=[cz.get_qubit_pulses(ordered_pair[1]).qf_pulses[0]], - type=SweeperType.ABSOLUTE, + type=SweeperType.FACTOR, ) + + data.cz_amplitude[ordered_pair] = ( + cz.get_qubit_pulses(ordered_pair[1]).qf_pulses[0].amplitude + ) + data.sweetspot[ordered_pair] = platform.qubits[ordered_pair[1]].sweetspot sweeper_duration = Sweeper( Parameter.duration, delta_duration_range, @@ -186,7 +199,7 @@ def _aquisition( ordered_pair[0], ordered_pair[1], delta_duration_range, - delta_amplitude_range, + delta_amplitude_range * data.cz_amplitude[ordered_pair], results[ordered_pair[0]].magnitude, results[ordered_pair[1]].magnitude, ) @@ -309,8 +322,12 @@ def _plot(data: ChevronData, fit: ChevronResults, target: QubitPairId): fitting_report = table_html( table_dict( target[1], - ["CZ amplitude", "CZ duration"], - [fit.amplitude[target], fit.duration[target]], + ["CZ amplitude", "CZ duration", "Bias point"], + [ + fit.amplitude[target], + fit.duration[target], + fit.amplitude[target] + data.sweetspot[target], + ], ) ) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index a22ec8c09..d73c4043b 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -414,8 +414,8 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): np.round( fit.virtual_phase[tuple(sorted(target))][target_q], 4 ), - np.round(data.amplitudes[qubits]), - np.round(data.durations[qubits]), + np.round(data.amplitudes[qubits], 4), + np.round(data.durations[qubits], 4), np.round(fit.leakage[tuple(sorted(target))][control_q], 4), ], ) diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index 53a8b593f..331796d84 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -558,9 +558,9 @@ actions: operation: chevron targets: [[0, 2],[1,2]] parameters: - amplitude_min: 0.1 - amplitude_max: 0.6 - amplitude_step: 0.01 + amplitude_min_factor: 0.1 + amplitude_max_factor: 0.6 + amplitude_step_factor: 0.01 duration_min: 10 duration_max: 50 duration_step: 1 From d37042af695c86068b1bbb7604557995a753c575 Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Fri, 29 Mar 2024 01:17:17 +0400 Subject: [PATCH 07/13] refactor: Correct virtual phase and CZ angle given from fit --- .../two_qubit_interaction/cz_virtualz.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index d73c4043b..617f23682 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -220,8 +220,8 @@ def _acquisition( ) data.vphases[ord_pair] = dict(virtual_z_phase) theta = np.arange( - virtual_z_phase[target_q] + params.theta_start, - virtual_z_phase[target_q] + params.theta_end, + params.theta_start, + params.theta_end, params.theta_step, dtype=float, ) @@ -229,7 +229,7 @@ def _acquisition( Parameter.relative_phase, theta, pulses=[theta_pulse], - type=SweeperType.ABSOLUTE, + type=SweeperType.OFFSET, ) results = platform.sweep( sequence, @@ -294,7 +294,7 @@ def _fit( target_data, p0=pguess, bounds=( - (-np.max(target_data), -np.max(target_data), 0), + (0, -np.max(target_data), 0), (np.max(target_data), np.max(target_data), 2 * np.pi), ), ) @@ -311,9 +311,11 @@ def _fit( fitted_parameters[target_q, control_q, "X"][2] - fitted_parameters[target_q, control_q, "I"][2] ) - virtual_phase[pair][target_q] = -fitted_parameters[ - target_q, control_q, "I" - ][2] + virtual_phase[pair][target_q] = ( + fitted_parameters[target_q, control_q, "I"][2] + + data.vphases[pair][target_q] + ) + # leakage estimate: L = m /2 # See NZ paper from Di Carlo # approximation which does not need qutrits @@ -425,16 +427,16 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): fig1.update_layout( title_text=f"Phase correction Qubit {qubits[0]}", showlegend=True, - xaxis1_title="theta [rad] + virtual phase[rad]", - xaxis2_title="theta [rad] + virtual phase [rad]", + xaxis1_title="Virtual phase[rad]", + xaxis2_title="Virtual phase [rad]", yaxis_title="Probability of State 0", ) fig2.update_layout( title_text=f"Phase correction Qubit {qubits[1]}", showlegend=True, - xaxis1_title="theta [rad] + virtual phase[rad]", - xaxis2_title="theta [rad] + virtual phase[rad]", + xaxis1_title="Virtual phase[rad]", + xaxis2_title="Virtual phase[rad]", yaxis_title="Probability of State 0", ) @@ -444,7 +446,6 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): def _update(results: CZVirtualZResults, platform: Platform, target: QubitPairId): # FIXME: quick fix for qubit order qubit_pair = tuple(sorted(target)) - # FIXME: the virtual phase should be corrected with a negative sign? target = tuple(sorted(target)) update.virtual_phases(results.virtual_phase[target], platform, target) From dfff6e8d72f58f1b7e88726961608e8a58bc5948 Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Fri, 29 Mar 2024 02:10:01 +0400 Subject: [PATCH 08/13] refactor: Shift plot to relative phase --- .../two_qubit_interaction/cz_virtualz.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index 617f23682..042be9646 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -227,9 +227,9 @@ def _acquisition( ) sweeper = Sweeper( Parameter.relative_phase, - theta, + theta - data.vphases[pair][target_q], pulses=[theta_pulse], - type=SweeperType.OFFSET, + type=SweeperType.ABSOLUTE, ) results = platform.sweep( sequence, @@ -290,7 +290,7 @@ def _fit( try: popt, _ = curve_fit( fit_function, - np.array(data.thetas) + data.vphases[pair][target], + np.array(data.thetas) - data.vphases[pair][target], target_data, p0=pguess, bounds=( @@ -311,10 +311,9 @@ def _fit( fitted_parameters[target_q, control_q, "X"][2] - fitted_parameters[target_q, control_q, "I"][2] ) - virtual_phase[pair][target_q] = ( - fitted_parameters[target_q, control_q, "I"][2] - + data.vphases[pair][target_q] - ) + virtual_phase[pair][target_q] = fitted_parameters[target_q, control_q, "I"][ + 2 + ] # leakage estimate: L = m /2 # See NZ paper from Di Carlo @@ -390,7 +389,7 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): go.Scatter( x=angle_range + data.vphases[qubits][target_q], y=fit_function( - angle_range + data.vphases[qubits][target_q], + angle_range - data.vphases[qubits][target_q], *fitted_parameters, ), name="Fit", From 6c0720af0867d730f160b27a85f7aa94bb92c33f Mon Sep 17 00:00:00 2001 From: andrea-pasquale Date: Fri, 29 Mar 2024 17:50:38 +0400 Subject: [PATCH 09/13] fix: Add try-except block --- .../two_qubit_interaction/cz_virtualz.py | 45 ++++++++++--------- .../cz_virtualz_signal.py | 6 +-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index 042be9646..8cec5e7c4 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -227,7 +227,7 @@ def _acquisition( ) sweeper = Sweeper( Parameter.relative_phase, - theta - data.vphases[pair][target_q], + theta - data.vphases[ord_pair][target_q], pulses=[theta_pulse], type=SweeperType.ABSOLUTE, ) @@ -303,27 +303,30 @@ def _fit( except Exception as e: log.warning(f"CZ fit failed for pair ({target, control}) due to {e}.") - for target_q, control_q in ( - pair, - list(pair)[::-1], - ): - cz_angle[target_q, control_q] = abs( - fitted_parameters[target_q, control_q, "X"][2] - - fitted_parameters[target_q, control_q, "I"][2] - ) - virtual_phase[pair][target_q] = fitted_parameters[target_q, control_q, "I"][ - 2 - ] - - # leakage estimate: L = m /2 - # See NZ paper from Di Carlo - # approximation which does not need qutrits - leakage[pair][control_q] = 0.5 * float( - np.mean( - data[pair][target_q, control_q, "X"].control - - data[pair][target_q, control_q, "I"].control + try: + for target_q, control_q in ( + pair, + list(pair)[::-1], + ): + cz_angle[target_q, control_q] = abs( + fitted_parameters[target_q, control_q, "X"][2] + - fitted_parameters[target_q, control_q, "I"][2] ) - ) + virtual_phase[pair][target_q] = fitted_parameters[ + target_q, control_q, "I" + ][2] + + # leakage estimate: L = m /2 + # See NZ paper from Di Carlo + # approximation which does not need qutrits + leakage[pair][control_q] = 0.5 * float( + np.mean( + data[pair][target_q, control_q, "X"].control + - data[pair][target_q, control_q, "I"].control + ) + ) + except KeyError: + pass # exception covered above return CZVirtualZResults( cz_angle=cz_angle, diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py index 35d924a74..482477cf9 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py @@ -91,14 +91,14 @@ def _acquisition( ) data.vphases[ord_pair] = dict(virtual_z_phase) theta = np.arange( - virtual_z_phase[target_q] + params.theta_start, - virtual_z_phase[target_q] + params.theta_end, + params.theta_start, + params.theta_end, params.theta_step, dtype=float, ) sweeper = Sweeper( Parameter.relative_phase, - theta, + theta - data.vphases[ord_pair][target_q], pulses=[theta_pulse], type=SweeperType.ABSOLUTE, ) From e5d186d50b1a7e4a8298f15bea9be241f37eaab6 Mon Sep 17 00:00:00 2001 From: Andrea Pasquale Date: Wed, 3 Apr 2024 15:55:33 +0400 Subject: [PATCH 10/13] fix: Remove commented code Co-authored-by: Edoardo Pedicillo --- .../characterization/two_qubit_interaction/tune_landscape.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py index ad9224255..13e729dc3 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py @@ -218,11 +218,6 @@ def _plot(data: TuneLandscapeData, fit: TuneLandscapeResults, target: QubitPairI return [fig1, fig2], "" -# def _update(results: CZVirtualZResults, platform: Platform, qubit_pair: QubitPairId): -# # FIXME: quick fix for qubit order -# qubit_pair = tuple(sorted(qubit_pair)) -# update.virtual_phases(results.virtual_phase[qubit_pair], platform, qubit_pair) - tune_landscape = Routine(_acquisition, _fit, _plot, two_qubit_gates=True) """CZ virtual Z correction routine.""" From 6ecb44afc9cc126a237e07ed3452a994151a62df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:55:43 +0000 Subject: [PATCH 11/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../characterization/two_qubit_interaction/tune_landscape.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py index 13e729dc3..059955c8c 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py @@ -218,6 +218,5 @@ def _plot(data: TuneLandscapeData, fit: TuneLandscapeResults, target: QubitPairI return [fig1, fig2], "" - tune_landscape = Routine(_acquisition, _fit, _plot, two_qubit_gates=True) """CZ virtual Z correction routine.""" From 6b7229f078a2973b204eecc77ce50c73972482bb Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 4 Apr 2024 12:25:21 +0400 Subject: [PATCH 12/13] fix: Juan suggestions --- .../two_qubit_interaction/cz_virtualz.py | 26 ++++++++++++++----- .../cz_virtualz_signal.py | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py index 8cec5e7c4..37a3df2ef 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz.py @@ -319,6 +319,7 @@ def _fit( # leakage estimate: L = m /2 # See NZ paper from Di Carlo # approximation which does not need qutrits + # https://arxiv.org/pdf/1903.02492.pdf leakage[pair][control_q] = 0.5 * float( np.mean( data[pair][target_q, control_q, "X"].control @@ -405,12 +406,10 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): fitting_report.add( table_html( table_dict( - [target_q, target_q, qubits[1], qubits[1], control_q], + [target_q, target_q, control_q], [ "CZ angle [rad]", "Virtual Z phase [rad]", - "Flux pulse amplitude [a.u.]", - "Flux pulse duration [ns]", "Leakage [a.u.]", ], [ @@ -418,20 +417,33 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): np.round( fit.virtual_phase[tuple(sorted(target))][target_q], 4 ), - np.round(data.amplitudes[qubits], 4), - np.round(data.durations[qubits], 4), np.round(fit.leakage[tuple(sorted(target))][control_q], 4), ], ) ) ) + fitting_report.add( + table_html( + table_dict( + [qubits[1], qubits[1]], + [ + "Flux pulse amplitude [a.u.]", + "Flux pulse duration [ns]", + ], + [ + np.round(data.amplitudes[qubits], 4), + np.round(data.durations[qubits], 4), + ], + ) + ) + ) fig1.update_layout( title_text=f"Phase correction Qubit {qubits[0]}", showlegend=True, xaxis1_title="Virtual phase[rad]", xaxis2_title="Virtual phase [rad]", - yaxis_title="Probability of State 0", + yaxis_title="State 0 Probability", ) fig2.update_layout( @@ -439,7 +451,7 @@ def _plot(data: CZVirtualZData, fit: CZVirtualZResults, target: QubitPairId): showlegend=True, xaxis1_title="Virtual phase[rad]", xaxis2_title="Virtual phase[rad]", - yaxis_title="Probability of State 0", + yaxis_title="State 0 Probability", ) return [fig1, fig2], "".join(fitting_report) # target and control qubit diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py index 482477cf9..ae9587ca5 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/cz_virtualz_signal.py @@ -46,7 +46,7 @@ def _acquisition( targets: list[QubitPairId], ) -> CZVirtualZSignalData: r""" - Acquisition for CZVirtualZ. + Acquisition for CZVirtualZ. See https://arxiv.org/pdf/1904.06560.pdf Check the two-qubit landscape created by a flux pulse of a given duration and amplitude. From 0e69f4141426ef3e7f69d53c0108c220c607e764 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 4 Apr 2024 12:41:21 +0400 Subject: [PATCH 13/13] refactor: remove tune landscape --- .../protocols/characterization/__init__.py | 2 - .../two_qubit_interaction/__init__.py | 1 - .../two_qubit_interaction/tune_landscape.py | 222 ------------------ tests/runcards/protocols.yml | 27 --- 4 files changed, 252 deletions(-) delete mode 100644 src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py diff --git a/src/qibocal/protocols/characterization/__init__.py b/src/qibocal/protocols/characterization/__init__.py index c66c992c6..0a1d64d0e 100644 --- a/src/qibocal/protocols/characterization/__init__.py +++ b/src/qibocal/protocols/characterization/__init__.py @@ -62,7 +62,6 @@ chsh_pulses, cz_virtualz, cz_virtualz_signal, - tune_landscape, ) @@ -123,7 +122,6 @@ class Operation(Enum): coupler_resonator_spectroscopy = coupler_resonator_spectroscopy coupler_qubit_spectroscopy = coupler_qubit_spectroscopy cz_virtualz_signal = cz_virtualz_signal - tune_landscape = tune_landscape coupler_chevron = coupler_chevron flipping_signal = flipping_signal calibrate_state_discrimination = calibrate_state_discrimination diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py index 233c25676..e9f98127d 100644 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py +++ b/src/qibocal/protocols/characterization/two_qubit_interaction/__init__.py @@ -2,4 +2,3 @@ from .chsh import chsh_circuits, chsh_pulses from .cz_virtualz import cz_virtualz from .cz_virtualz_signal import cz_virtualz_signal -from .tune_landscape import tune_landscape diff --git a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py b/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py deleted file mode 100644 index 059955c8c..000000000 --- a/src/qibocal/protocols/characterization/two_qubit_interaction/tune_landscape.py +++ /dev/null @@ -1,222 +0,0 @@ -"""CZ virtual correction experiment for two qubit gates, tune landscape.""" - -from dataclasses import dataclass, field -from typing import Optional - -import numpy as np -import numpy.typing as npt -import plotly.graph_objects as go -from plotly.subplots import make_subplots -from qibolab.platform import Platform -from qibolab.qubits import QubitPairId - -from qibocal.auto.operation import Data, Parameters, Results, Routine - -from .cz_virtualz import cz_virtualz - -COLORAXIS = ["coloraxis2", "coloraxis1"] - - -@dataclass -class TuneLandscapeParameters(Parameters): - """CzVirtualZ runcard inputs.""" - - amplitude_min: float - """Amplitude minimum.""" - amplitude_max: float - """Amplitude maximum.""" - amplitude_step: float - """Amplitude step.""" - duration_min: float - """Duration minimum.""" - duration_max: float - """Duration maximum.""" - duration_step: float - """Duration step.""" - dt: Optional[float] = 20 - """Time delay between flux pulses and readout.""" - parking: bool = True - """Wether to park non interacting qubits or not.""" - - -@dataclass -class TuneLandscapeResults(Results): - """CzVirtualZ outputs when fitting will be done.""" - - -TuneLandscapeType = np.dtype( - [ - ("leakage", np.float64), - ("cz_angle", np.float64), - ("phase", np.float64), - ("length", np.float64), - ("amp", np.float64), - ] -) - - -@dataclass -class TuneLandscapeData(Data): - """CZVirtualZ data.""" - - data: dict[tuple, npt.NDArray[TuneLandscapeType]] = field(default_factory=dict) - - def __getitem__(self, pair): - return { - index: value - for index, value in self.data.items() - if set(pair).issubset(index) - } - - def register_qubit( - self, target_q, control_q, duration, amplitude, leakage, cz_angle, phase - ): - """Store output for single qubit.""" - ar = np.empty((1,), dtype=TuneLandscapeType) - ar["length"] = duration - ar["amp"] = amplitude - ar["leakage"] = leakage - ar["cz_angle"] = cz_angle - ar["phase"] = phase - - if (target_q, control_q) in self.data: - self.data[target_q, control_q] = np.rec.array( - np.concatenate((self.data[target_q, control_q], ar)) - ) - else: - self.data[target_q, control_q] = np.rec.array(ar) - - -# TODO: make acquisition working regardless of the qubits order -def _acquisition( - params: TuneLandscapeParameters, - platform: Platform, - targets: list[QubitPairId], -) -> TuneLandscapeData: - r""" - Acquisition for tune landscape. - - Currently this experiments perform the CZVirtualZ protocols for different - amplitudes and durations of the flux pulse. The leakage and the CZ angle are - plotted for each configuration. - """ - - data = TuneLandscapeData() - amplitude_range = np.arange( - params.amplitude_min, - params.amplitude_max, - params.amplitude_step, - ) - - duration_range = np.arange( - params.duration_min, params.duration_max, params.duration_step - ) - - for amplitude in amplitude_range: - for duration in duration_range: - cz_data, _ = cz_virtualz.acquisition( - params=cz_virtualz.parameters_type.load( - dict( - theta_start=0, - theta_end=7, - theta_step=0.1, - flux_pulse_amplitude=amplitude, - flux_pulse_duration=duration, - ) - ), - platform=platform, - targets=targets, - ) - cz_fit, _ = cz_virtualz.fit(cz_data) - - for pair in targets: - for target_q, control_q in ( - pair, - list(pair)[::-1], - ): - data.register_qubit( - target_q, - control_q, - duration, - amplitude, - leakage=cz_fit.leakage[pair][control_q], - cz_angle=cz_fit.cz_angle[pair], - phase=cz_fit.virtual_phase[pair][target_q], - ) - - return data - - -def _fit( - data: TuneLandscapeData, -) -> TuneLandscapeResults: - return TuneLandscapeResults() - - -def _plot(data: TuneLandscapeData, fit: TuneLandscapeResults, target: QubitPairId): - pair_data = data[target] - qubits = next(iter(pair_data))[:2] - fig1 = make_subplots( - rows=1, - cols=2, - subplot_titles=( - f"Leakage Qubit {qubits[0]}", - f"Leakage Qubit {qubits[1]}", - ), - ) - fig2 = make_subplots( - rows=1, - cols=2, - subplot_titles=( - f"CZ angle Qubit {qubits[0]}", - f"CZ angle Qubit {qubits[1]}", - ), - ) - - for target, control in pair_data: - fig1.add_trace( - go.Heatmap( - x=pair_data[target, control].length, - y=pair_data[target, control].amp, - z=abs( - pair_data[target, control].leakage - ), # TODO: check if you need abs - name=f"Leakage qubit {target}", - colorbar=dict( - tickmode="array", - tickvals=[0, 0.1, 0.2, 0.3, 0.4], - ticktext=["0", "0.1", "0.2", "0.3", "0.4"], # Set the tick labels - ), - ), - row=1, - col=1 if (target, control) == qubits else 2, - ) - - fig2.add_trace( - go.Heatmap( - x=pair_data[target, control].length, - y=pair_data[target, control].amp, - z=pair_data[target, control].cz_angle, - colorscale="RdBu", - colorbar=dict( - tickmode="array", - tickvals=[0, np.pi / 2, np.pi, 3 * np.pi / 2, 2 * np.pi], - ticktext=[ - "0", - "1.57", - "3.14", - "4.71", - "6.28", - ], # Set the tick labels - ), - name=f"CZ angle [rad] qubit {target}", - ), - row=1, - col=1 if (target, control) == qubits else 2, - ) - - return [fig1, fig2], "" - - -tune_landscape = Routine(_acquisition, _fit, _plot, two_qubit_gates=True) -"""CZ virtual Z correction routine.""" diff --git a/tests/runcards/protocols.yml b/tests/runcards/protocols.yml index bf5a46d7f..ba9d7d37c 100644 --- a/tests/runcards/protocols.yml +++ b/tests/runcards/protocols.yml @@ -678,33 +678,6 @@ actions: dt: 0 parking: True - - id: tune landscape signal - priority: 0 - operation: cz_virtualz_signal - targets: [[0, 2],[1,2]] - parameters: - theta_start: 0 - theta_end: 180 - theta_step: 10 - flux_pulse_amplitude: 0.5 - flux_pulse_duration: 10 - dt: 0 - parking: True - - - - id: tune landscape - priority: 0 - operation: tune_landscape - targets: [[0, 2],[1,2]] - parameters: - amplitude_min: 0.1 - amplitude_max: 0.2 - amplitude_step: 0.01 - duration_min: 10 - duration_max: 20 - duration_step: 1 - - - id : resonator_frequency operation: resonator_frequency parameters: