From c4d9f98aa573ff116c7910ec4b379d14f1a3fa6a Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 23 Oct 2023 17:09:44 +0400 Subject: [PATCH 01/28] fix probabilities --- src/qibolab/instruments/zhinst.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 52a3ba2c46..2f28a7eee7 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -528,6 +528,7 @@ def play(self, qubits, couplers, sequence, options): data = ( np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) + data = np.ones(data.shape) - data.real # FIXME: Probability inversion results[ropulse.pulse.serial] = options.results_type(data) results[ropulse.pulse.qubit] = options.results_type(data) else: @@ -1043,6 +1044,7 @@ def sweep(self, qubits, couplers, sequence: PulseSequence, options, *sweepers): np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) data = data.real + data = np.ones(data.shape) - data # FIXME: Probability inversion results[self.sequence[f"readout{q}"][i].pulse.serial] = options.results_type(data) results[self.sequence[f"readout{q}"][i].pulse.qubit] = options.results_type(data) else: From 899dc25835ff565e12b622f62be6ac2df4ab4b92 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Wed, 25 Oct 2023 13:38:14 +0400 Subject: [PATCH 02/28] prototype for kernels --- src/qibolab/instruments/zhinst.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 2f28a7eee7..92c30f0580 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -4,6 +4,7 @@ import os from collections import defaultdict from dataclasses import dataclass, replace +from pathlib import Path from typing import Tuple import laboneq._token @@ -17,11 +18,13 @@ from qibo.config import log from qibolab import AcquisitionType, AveragingMode, ExecutionParameters -from qibolab.instruments.abstract import INSTRUMENTS_DATA_FOLDER, Controller +from qibolab.instruments.abstract import Controller from qibolab.instruments.port import Port from qibolab.pulses import CouplerFluxPulse, FluxPulse, PulseSequence, PulseType from qibolab.sweeper import Parameter +KERNELS_FOLDER = Path.home() / "qibolab" / "src" / "qibolab" / "instruments" / "data" + # this env var just needs to be set os.environ["LABONEQ_TOKEN"] = "not required" laboneq._token.is_valid_token = lambda _token: True # pylint: disable=W0212 @@ -895,19 +898,26 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): pulse.zhpulse.uid += str(i) # Integration weights definition or load from the chip folder - weights_file = ( - INSTRUMENTS_DATA_FOLDER / f"{self.chip}/weights/integration_weights_optimization_qubit_{q}.npy" - ) + weights_file = KERNELS_FOLDER / f"{self.chip}/weights/kernels.npz" if weights_file.is_file(): - samples = np.load( - weights_file, - allow_pickle=True, - ) + # samples = np.load( + # weights_file, + # allow_pickle=True, + # ) + from qibocal.auto.serialize import load + + raw_data_dict = dict(np.load(weights_file)) + samples = {} + + for data_key, array in raw_data_dict.items(): + samples[load(data_key)] = np.rec.array(array) + if acquisition_type == lo.AcquisitionType.DISCRIMINATION: weight = lo.pulse_library.sampled_pulse_complex( uid="weight" + pulse.zhpulse.uid, # samples=samples[0] * np.exp(1j * qubit.iq_angle), - samples=samples[0] * np.exp(1j * iq_angle), + # samples=samples[0] * np.exp(1j * iq_angle), + samples=samples[q], ) else: weight = lo.pulse_library.sampled_pulse_complex( From f49378d7b2c1b6c3ef9d82811121c05d81d3b372 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 23 Oct 2023 17:09:44 +0400 Subject: [PATCH 03/28] reorder --- src/qibolab/instruments/zhinst.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 92c30f0580..72ff1b94fa 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -531,7 +531,6 @@ def play(self, qubits, couplers, sequence, options): data = ( np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) - data = np.ones(data.shape) - data.real # FIXME: Probability inversion results[ropulse.pulse.serial] = options.results_type(data) results[ropulse.pulse.qubit] = options.results_type(data) else: @@ -900,10 +899,6 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): # Integration weights definition or load from the chip folder weights_file = KERNELS_FOLDER / f"{self.chip}/weights/kernels.npz" if weights_file.is_file(): - # samples = np.load( - # weights_file, - # allow_pickle=True, - # ) from qibocal.auto.serialize import load raw_data_dict = dict(np.load(weights_file)) @@ -915,8 +910,6 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): if acquisition_type == lo.AcquisitionType.DISCRIMINATION: weight = lo.pulse_library.sampled_pulse_complex( uid="weight" + pulse.zhpulse.uid, - # samples=samples[0] * np.exp(1j * qubit.iq_angle), - # samples=samples[0] * np.exp(1j * iq_angle), samples=samples[q], ) else: @@ -1054,7 +1047,6 @@ def sweep(self, qubits, couplers, sequence: PulseSequence, options, *sweepers): np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) data = data.real - data = np.ones(data.shape) - data # FIXME: Probability inversion results[self.sequence[f"readout{q}"][i].pulse.serial] = options.results_type(data) results[self.sequence[f"readout{q}"][i].pulse.qubit] = options.results_type(data) else: From 0da941a95db26a7f5c104a909f9ae21f0b9d0584 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Fri, 1 Dec 2023 15:36:07 +0400 Subject: [PATCH 04/28] fixes --- src/qibolab/instruments/zhinst.py | 47 +++++++++++-------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 55a0fbd346..75b0a60fca 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -928,31 +928,18 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): time=self.sequence_qibo.start * NANO_TO_SECONDS, ) - if i == 0: - # Integration weights definition or load from the chip folder - weights_file = weights_file = KERNELS_FOLDER / f"{self.chip}/weights/kernels.npz" - if weights_file.is_file(): - from qibocal.auto.serialize import load - - raw_data_dict = dict(np.load(weights_file)) - samples = {} - - for data_key, array in raw_data_dict.items(): - samples[load(data_key)] = np.rec.array(array) + weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / "kernels.npz" + if weights_file.is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: + kernels = np.load(weights_file) + weight = lo.pulse_library.sampled_pulse_complex( + uid="weight" + str(q), + # Do we need the angle ? + samples=kernels[str(q)] * np.exp(1j * iq_angle), + # samples=kernels[str(q)], + ) - if acquisition_type == lo.AcquisitionType.DISCRIMINATION: - weight = lo.pulse_library.sampled_pulse_complex( - uid="weight" + str(q), - # samples=samples[q] * np.exp(1j * iq_angle), - samples=samples[q], - ) - else: - weight = lo.pulse_library.sampled_pulse_complex( - uid="weight" + str(q), - samples=samples[q], - ) - else: - # We adjust for smearing and remove smearing/2 at the end + else: + if i == 0: exp.delay( signal=f"acquire{q}", time=self.smearing * NANO_TO_SECONDS, @@ -975,12 +962,12 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): amplitude=1, ) weights[q] = weight - elif i != 0: - exp.delay( - signal=f"acquire{q}", - time=self.smearing * NANO_TO_SECONDS, - ) - weight = weights[q] + elif i != 0: + exp.delay( + signal=f"acquire{q}", + time=self.smearing * NANO_TO_SECONDS, + ) + weight = weights[q] measure_pulse_parameters = {"phase": 0} From 91e4a7963019db3ed3a977211ac57def92290f05 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 11:28:02 +0400 Subject: [PATCH 05/28] Remove commented code and update kernel file name --- src/qibolab/instruments/zhinst.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 75b0a60fca..c6de57ae05 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -441,7 +441,7 @@ def register_readout_line(self, qubit, intermediate_frequency): ), range=qubit.feedback.power_range, port_delay=self.time_of_flight * NANO_TO_SECONDS, - threshold=qubit.threshold, + # threshold=qubit.threshold, #TODO: remove ) def register_drive_line(self, qubit, intermediate_frequency): @@ -928,22 +928,18 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): time=self.sequence_qibo.start * NANO_TO_SECONDS, ) - weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / "kernels.npz" + weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" if weights_file.is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: kernels = np.load(weights_file) weight = lo.pulse_library.sampled_pulse_complex( uid="weight" + str(q), # Do we need the angle ? - samples=kernels[str(q)] * np.exp(1j * iq_angle), - # samples=kernels[str(q)], + # samples=kernels[str(q)] * np.exp(1j * iq_angle), + samples=kernels[str(q)], ) else: if i == 0: - exp.delay( - signal=f"acquire{q}", - time=self.smearing * NANO_TO_SECONDS, - ) if acquisition_type == lo.AcquisitionType.DISCRIMINATION: weight = lo.pulse_library.sampled_pulse_complex( samples=np.ones( @@ -961,12 +957,9 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): - 1.5 * self.smearing * NANO_TO_SECONDS, amplitude=1, ) + weights[q] = weight elif i != 0: - exp.delay( - signal=f"acquire{q}", - time=self.smearing * NANO_TO_SECONDS, - ) weight = weights[q] measure_pulse_parameters = {"phase": 0} @@ -989,7 +982,6 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): measure_pulse_parameters=measure_pulse_parameters, measure_pulse_amplitude=None, acquire_delay=self.time_of_flight * NANO_TO_SECONDS, - # reset_delay=relaxation_time * NANO_TO_SECONDS, reset_delay=reset_delay, ) From f0df31a0edb401a11a1720b96eced211a9f2ff0e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 07:28:55 +0000 Subject: [PATCH 06/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibolab/instruments/zhinst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index c6de57ae05..74a0184886 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -957,7 +957,7 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): - 1.5 * self.smearing * NANO_TO_SECONDS, amplitude=1, ) - + weights[q] = weight elif i != 0: weight = weights[q] From 1dac5dc1c048382b306269461d708014257e2e15 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 13:01:01 +0400 Subject: [PATCH 07/28] Fix register_readout_line options bug --- src/qibolab/instruments/zhinst.py | 41 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 74a0184886..dff17f9b04 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -380,6 +380,7 @@ def calibration_step(self, qubits, couplers, options): self.register_readout_line( qubit=qubit, intermediate_frequency=qubit.readout_frequency - qubit.readout.local_oscillator.frequency, + options=options, ) if options.fast_reset is not False: if len(self.sequence[f"drive{qubit.name}"]) == 0: @@ -389,7 +390,7 @@ def calibration_step(self, qubits, couplers, options): ) self.device_setup.set_calibration(self.calibration) - def register_readout_line(self, qubit, intermediate_frequency): + def register_readout_line(self, qubit, intermediate_frequency, options): """Registers qubit measure and acquire lines to calibration and signal map. Note @@ -430,19 +431,27 @@ def register_readout_line(self, qubit, intermediate_frequency): self.signal_map[f"acquire{q}"] = self.device_setup.logical_signal_groups[f"q{q}"].logical_signals[ "acquire_line" ] - self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( - oscillator=lo.Oscillator( - frequency=intermediate_frequency, - modulation_type=lo.ModulationType.SOFTWARE, - ), - local_oscillator=lo.Oscillator( - uid="lo_shfqa_a" + str(q), - frequency=int(qubit.readout.local_oscillator.frequency), - ), - range=qubit.feedback.power_range, - port_delay=self.time_of_flight * NANO_TO_SECONDS, - # threshold=qubit.threshold, #TODO: remove - ) + weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" + if weights_file.is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: + # Remove software modulation as it's already included on the kernels + self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( + oscillator=None, + local_oscillator=None, + range=qubit.feedback.power_range, + port_delay=self.time_of_flight * NANO_TO_SECONDS, + # threshold=qubit.threshold, #TODO: remove + ) + else: + self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( + oscillator=lo.Oscillator( + frequency=intermediate_frequency, + modulation_type=lo.ModulationType.SOFTWARE, + ), + local_oscillator=None, + range=qubit.feedback.power_range, + port_delay=self.time_of_flight * NANO_TO_SECONDS, + # threshold=qubit.threshold, #TODO: remove + ) def register_drive_line(self, qubit, intermediate_frequency): """Registers qubit drive line to calibration and signal map.""" @@ -933,9 +942,7 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): kernels = np.load(weights_file) weight = lo.pulse_library.sampled_pulse_complex( uid="weight" + str(q), - # Do we need the angle ? - # samples=kernels[str(q)] * np.exp(1j * iq_angle), - samples=kernels[str(q)], + samples=kernels[str(q)] * np.exp(1j * iq_angle), ) else: From 4951df9b0626abc004b5b1f8027eeb35e3be676d Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 14:58:11 +0400 Subject: [PATCH 08/28] keep compatibility with threshold --- src/qibolab/instruments/zhinst.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index dff17f9b04..cc467e59e6 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -434,23 +434,30 @@ def register_readout_line(self, qubit, intermediate_frequency, options): weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" if weights_file.is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: # Remove software modulation as it's already included on the kernels + print("aqui") self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=None, - local_oscillator=None, range=qubit.feedback.power_range, port_delay=self.time_of_flight * NANO_TO_SECONDS, - # threshold=qubit.threshold, #TODO: remove ) - else: + elif weights_file.is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: + self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( + oscillator=lo.Oscillator( + frequency=intermediate_frequency, + modulation_type=lo.ModulationType.SOFTWARE, + ), + range=qubit.feedback.power_range, + port_delay=self.time_of_flight * NANO_TO_SECONDS, + threshold=qubit.threshold, # To keep compatibility with angle and threshold discrimination + ) + elif not weights_file.is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=lo.Oscillator( frequency=intermediate_frequency, modulation_type=lo.ModulationType.SOFTWARE, ), - local_oscillator=None, range=qubit.feedback.power_range, port_delay=self.time_of_flight * NANO_TO_SECONDS, - # threshold=qubit.threshold, #TODO: remove ) def register_drive_line(self, qubit, intermediate_frequency): @@ -552,7 +559,7 @@ def play(self, qubits, couplers, sequence, options): data = ( np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) - data = np.ones(data.shape) - data.real # Probability inversion patch + data = np.ones(data.shape) - data.real # Probability inversion results[ropulse.pulse.serial] = options.results_type(data) results[ropulse.pulse.qubit] = options.results_type(data) else: @@ -1077,8 +1084,7 @@ def sweep(self, qubits, couplers, sequence: PulseSequence, options, *sweepers): data = ( np.array([exp_res]) if options.averaging_mode is AveragingMode.CYCLIC else np.array(exp_res) ) - data = data.real - data = np.ones(data.shape) - data # Probability inversion patch + data = np.ones(data.shape) - data.real # Probability inversion results[self.sequence[f"readout{q}"][i].pulse.serial] = options.results_type(data) results[self.sequence[f"readout{q}"][i].pulse.qubit] = options.results_type(data) else: From 451e815a4ffcc07b6218d528ce1472e53215ffe7 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 15:03:03 +0400 Subject: [PATCH 09/28] smearing --- src/qibolab/instruments/zhinst.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index cc467e59e6..1315be6d05 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -944,6 +944,11 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): time=self.sequence_qibo.start * NANO_TO_SECONDS, ) + exp.delay( + signal=f"acquire{q}", + time=self.smearing * NANO_TO_SECONDS, + ) + weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" if weights_file.is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: kernels = np.load(weights_file) From 698e4c9bb2a4a28f498a177da3d7234a8feff4d8 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 15:19:37 +0400 Subject: [PATCH 10/28] Add options parameter to register_readout_line test function --- tests/test_instruments_zhinst.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_instruments_zhinst.py b/tests/test_instruments_zhinst.py index e7cb3e6aeb..b63fae22d0 100644 --- a/tests/test_instruments_zhinst.py +++ b/tests/test_instruments_zhinst.py @@ -172,7 +172,12 @@ def test_zhinst_register_readout_line(dummy_qrc): platform = create_platform("zurich") platform.setup() IQM5q = platform.instruments["EL_ZURO"] - IQM5q.register_readout_line(platform.qubits[0], intermediate_frequency=int(1e6)) + + options = ExecutionParameters( + relaxation_time=300e-6, acquisition_type=AcquisitionType.INTEGRATION, averaging_mode=AveragingMode.CYCLIC + ) + + IQM5q.register_readout_line(platform.qubits[0], intermediate_frequency=int(1e6), options=options) assert "measure0" in IQM5q.signal_map assert "acquire0" in IQM5q.signal_map From 0859a5858a2970261de4269d161ce8b69c8e9b62 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 4 Dec 2023 18:17:26 +0400 Subject: [PATCH 11/28] Update kernel path for qubits --- src/qibolab/instruments/zhinst.py | 6 ++++-- src/qibolab/qubits.py | 3 +++ tests/dummy_qrc/zurich.yml | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 1315be6d05..4c7031390e 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -431,7 +431,8 @@ def register_readout_line(self, qubit, intermediate_frequency, options): self.signal_map[f"acquire{q}"] = self.device_setup.logical_signal_groups[f"q{q}"].logical_signals[ "acquire_line" ] - weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" + # weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" + weights_file = qubit.kernel_path / f"kernels_q{q}.npz" if weights_file.is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: # Remove software modulation as it's already included on the kernels print("aqui") @@ -949,7 +950,8 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): time=self.smearing * NANO_TO_SECONDS, ) - weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" + # weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" + weights_file = qubits[q].kernel_path / f"kernels_q{q}.npz" if weights_file.is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: kernels = np.load(weights_file) weight = lo.pulse_library.sampled_pulse_complex( diff --git a/src/qibolab/qubits.py b/src/qibolab/qubits.py index 77bca66f6d..9893cba565 100644 --- a/src/qibolab/qubits.py +++ b/src/qibolab/qubits.py @@ -1,4 +1,5 @@ from dataclasses import dataclass, field, fields +from pathlib import Path from typing import List, Optional, Tuple, Union from qibolab.channels import Channel @@ -89,6 +90,8 @@ class Qubit: native_gates: SingleQubitNatives = field(default_factory=SingleQubitNatives) + kernel_path: Optional[Path] = None + @property def channels(self): for name in CHANNEL_NAMES: diff --git a/tests/dummy_qrc/zurich.yml b/tests/dummy_qrc/zurich.yml index c092a38ca8..f9fa5cf72b 100644 --- a/tests/dummy_qrc/zurich.yml +++ b/tests/dummy_qrc/zurich.yml @@ -1,5 +1,6 @@ nqubits: 5 qubits: [0, 1, 2, 3, 4] +kernel_path: "qibolab_platforms_qrc/iqm5q_kernels" couplers: [0, 1, 3, 4] topology: {0: [0, 2], 1: [1, 2], 3: [2, 3], 4: [2, 4]} settings: From 4a920ccd30b08aa939d6f8f69e8cf81917ec6487 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 15:10:16 +0400 Subject: [PATCH 12/28] Add kernel path to Qubit class and update Zurich Controller to use kernel path --- src/qibolab/instruments/zhinst.py | 20 +++++++++----------- src/qibolab/qubits.py | 3 +-- src/qibolab/serialize.py | 3 +++ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 4c7031390e..2bcd9e8e19 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -313,6 +313,7 @@ def __init__(self, name, device_setup, use_emulation=False, time_of_flight=0.0, self.smearing = smearing self.chip = "iqm5q" "Parameters read from the runcard not part of ExecutionParameters" + self.kernels = defaultdict(Path) self.exp = None self.experiment = None @@ -431,17 +432,16 @@ def register_readout_line(self, qubit, intermediate_frequency, options): self.signal_map[f"acquire{q}"] = self.device_setup.logical_signal_groups[f"q{q}"].logical_signals[ "acquire_line" ] - # weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" - weights_file = qubit.kernel_path / f"kernels_q{q}.npz" - if weights_file.is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: - # Remove software modulation as it's already included on the kernels - print("aqui") + + if qubit.kernel_path: + self.kernels[q] = qubit.kernel_path / f"kernels_q{q}.npz" + if self.kernels[q].is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=None, range=qubit.feedback.power_range, port_delay=self.time_of_flight * NANO_TO_SECONDS, ) - elif weights_file.is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: + elif self.kernels[q].is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=lo.Oscillator( frequency=intermediate_frequency, @@ -451,7 +451,7 @@ def register_readout_line(self, qubit, intermediate_frequency, options): port_delay=self.time_of_flight * NANO_TO_SECONDS, threshold=qubit.threshold, # To keep compatibility with angle and threshold discrimination ) - elif not weights_file.is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: + elif not self.kernels[q].is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=lo.Oscillator( frequency=intermediate_frequency, @@ -950,10 +950,8 @@ def measure_relax(self, exp, qubits, relaxation_time, acquisition_type): time=self.smearing * NANO_TO_SECONDS, ) - # weights_file = KERNELS_FOLDER / str(self.chip) / "weights" / f"kernels_q{q}.npz" - weights_file = qubits[q].kernel_path / f"kernels_q{q}.npz" - if weights_file.is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: - kernels = np.load(weights_file) + if self.kernels[q].is_file() and acquisition_type == lo.AcquisitionType.DISCRIMINATION: + kernels = np.load(self.kernels[q]) weight = lo.pulse_library.sampled_pulse_complex( uid="weight" + str(q), samples=kernels[str(q)] * np.exp(1j * iq_angle), diff --git a/src/qibolab/qubits.py b/src/qibolab/qubits.py index 9893cba565..8757faacb9 100644 --- a/src/qibolab/qubits.py +++ b/src/qibolab/qubits.py @@ -38,6 +38,7 @@ class Qubit: """ name: QubitId + kernel_path: Optional[Path] = None bare_resonator_frequency: int = 0 readout_frequency: int = 0 @@ -90,8 +91,6 @@ class Qubit: native_gates: SingleQubitNatives = field(default_factory=SingleQubitNatives) - kernel_path: Optional[Path] = None - @property def channels(self): for name in CHANNEL_NAMES: diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 23ffb9c820..039f35f9bd 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -41,6 +41,9 @@ def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: objects. """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} + if runcard["kernel_path"]: + for qubit in qubits.values(): + qubit.kernel_path = Path(runcard["kernel_path"]) couplers = {} pairs = {} From 79fa12fa7d4a0352e3950b9467a0d83f34faf919 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:10:55 +0000 Subject: [PATCH 13/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibolab/instruments/zhinst.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 2bcd9e8e19..e5198abe89 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -313,7 +313,7 @@ def __init__(self, name, device_setup, use_emulation=False, time_of_flight=0.0, self.smearing = smearing self.chip = "iqm5q" "Parameters read from the runcard not part of ExecutionParameters" - self.kernels = defaultdict(Path) + self.kernels = defaultdict(Path) self.exp = None self.experiment = None @@ -432,7 +432,7 @@ def register_readout_line(self, qubit, intermediate_frequency, options): self.signal_map[f"acquire{q}"] = self.device_setup.logical_signal_groups[f"q{q}"].logical_signals[ "acquire_line" ] - + if qubit.kernel_path: self.kernels[q] = qubit.kernel_path / f"kernels_q{q}.npz" if self.kernels[q].is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: From 4b99f6e38e8a2007db8f5a0c0dfe1c9ecd7223d7 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 15:22:39 +0400 Subject: [PATCH 14/28] fix --- src/qibolab/serialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 039f35f9bd..1746dcb89f 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -41,7 +41,7 @@ def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: objects. """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} - if runcard["kernel_path"]: + if "kernel_path" in runcard: for qubit in qubits.values(): qubit.kernel_path = Path(runcard["kernel_path"]) From a4b6fd5180d288af0dd8dd80c321b661272155b3 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 15:24:42 +0400 Subject: [PATCH 15/28] remove unused --- src/qibolab/instruments/zhinst.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index e5198abe89..19dde9c413 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -25,8 +25,6 @@ from qibolab.qubits import Qubit from qibolab.sweeper import Parameter -KERNELS_FOLDER = Path.home() / "qibolab" / "src" / "qibolab" / "instruments" / "data" - # this env var just needs to be set os.environ["LABONEQ_TOKEN"] = "not required" laboneq._token.is_valid_token = lambda _token: True # pylint: disable=W0212 From 4c1f0fec8609e548412a893d3b5bf339a0900c3c Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 16:57:03 +0400 Subject: [PATCH 16/28] Add kernel_folder attribute to Platform class --- src/qibolab/platform.py | 2 ++ src/qibolab/qubits.py | 2 +- src/qibolab/serialize.py | 18 ++++++++++++++---- tests/dummy_qrc/zurich.py | 2 ++ tests/dummy_qrc/zurich.yml | 15 +++++++-------- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/qibolab/platform.py b/src/qibolab/platform.py index e3b61ed72a..12efb5da2c 100644 --- a/src/qibolab/platform.py +++ b/src/qibolab/platform.py @@ -54,6 +54,8 @@ class Platform: couplers: CouplerMap = field(default_factory=dict) """Dictionary mapping coupler names to :class:`qibolab.couplers.Coupler` objects.""" + kernel_folder: Optional[str] = None + """Folder where each qubit kernels are stored""" is_connected: bool = False """Flag for whether we are connected to the physical instruments.""" diff --git a/src/qibolab/qubits.py b/src/qibolab/qubits.py index 8757faacb9..beb5a2b3f9 100644 --- a/src/qibolab/qubits.py +++ b/src/qibolab/qubits.py @@ -38,7 +38,6 @@ class Qubit: """ name: QubitId - kernel_path: Optional[Path] = None bare_resonator_frequency: int = 0 readout_frequency: int = 0 @@ -77,6 +76,7 @@ class Qubit: # parameters for single shot classification threshold: Optional[float] = None iq_angle: float = 0.0 + kernel_path: Optional[Path] = None # required for mixers (not sure if it should be here) mixer_drive_g: float = 0.0 mixer_drive_phi: float = 0.0 diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 1746dcb89f..18defb4e27 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -41,9 +41,11 @@ def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: objects. """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} - if "kernel_path" in runcard: + if "kernel_folder" in runcard: for qubit in qubits.values(): - qubit.kernel_path = Path(runcard["kernel_path"]) + qubit.kernel_path = Path( + runcard["kernel_folder"] + runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] + ) couplers = {} pairs = {} @@ -94,7 +96,7 @@ def load_instrument_settings(runcard: dict, instruments: InstrumentMap) -> Instr return instruments -def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = None) -> dict: +def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = None, kernel_folder: str = None) -> dict: """Dump qubit and pair objects to a dictionary following the runcard format.""" native_gates = {"single_qubit": {q: qubit.native_gates.raw for q, qubit in qubits.items()}} @@ -111,6 +113,11 @@ def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = No characterization = { "single_qubit": {q: qubit.characterization for q, qubit in qubits.items()}, } + if kernel_folder: + for q in qubits: + characterization["single_qubit"][q]["kernel_path"] = str( + characterization["single_qubit"][q]["kernel_path"] + ).replace(kernel_folder, "") if couplers: characterization["coupler"] = {c.name: {"sweetspot": c.sweetspot} for c in couplers.values()} @@ -147,9 +154,12 @@ def dump_runcard(platform: Platform, path: Path): "topology": [list(pair) for pair in platform.pairs], "instruments": dump_instruments(platform.instruments), } + + if platform.kernel_folder: + settings["kernel_folder"] = platform.kernel_folder if platform.couplers: settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} - settings.update(dump_qubits(platform.qubits, platform.pairs, platform.couplers)) + settings.update(dump_qubits(platform.qubits, platform.pairs, platform.couplers, platform.kernel_folder)) path.write_text(yaml.dump(settings, sort_keys=False, indent=4, default_flow_style=None)) diff --git a/tests/dummy_qrc/zurich.py b/tests/dummy_qrc/zurich.py index b5d94c4e86..d7d2a65a24 100644 --- a/tests/dummy_qrc/zurich.py +++ b/tests/dummy_qrc/zurich.py @@ -19,6 +19,7 @@ RUNCARD = pathlib.Path(__file__).parent / "zurich.yml" N_QUBITS = 5 +KERNEL_FOLDER = "qibolab_platforms_qrc/iqm5q_kernels/" def create(runcard_path=RUNCARD): @@ -165,4 +166,5 @@ def create(runcard_path=RUNCARD): settings, resonator_type="2D", couplers=couplers, + kernel_folder=KERNEL_FOLDER, ) diff --git a/tests/dummy_qrc/zurich.yml b/tests/dummy_qrc/zurich.yml index f9fa5cf72b..e9c8122fb1 100644 --- a/tests/dummy_qrc/zurich.yml +++ b/tests/dummy_qrc/zurich.yml @@ -1,6 +1,5 @@ nqubits: 5 qubits: [0, 1, 2, 3, 4] -kernel_path: "qibolab_platforms_qrc/iqm5q_kernels" couplers: [0, 1, 3, 4] topology: {0: [0, 2], 1: [1, 2], 3: [2, 3], 4: [2, 4]} settings: @@ -8,6 +7,8 @@ settings: sampling_rate: 2.e+9 relaxation_time: 300_000 +kernel_folder: "qibolab_platforms_qrc/iqm5q_kernels/" + instruments: lo_readout: frequency: 5_500_000_000 @@ -246,12 +247,7 @@ characterization: # parameters for single shot classification threshold: 0.8836 iq_angle: -1.551 - # alpha: 217.492 MHz - # To save power values on the runcard - # ro_range_lp: -15 - # ro_range_hp: -15 - # qd_range: 0 - # flux_range: -0 + kernel_path: "kernel_q0" 1: readout_frequency: 4_931_000_000 @@ -261,6 +257,7 @@ characterization: sweetspot: 0.0 mean_gnd_states: [0, 0] mean_exc_states: [0, 0] + kernel_path: "kernel_q1" 2: readout_frequency: 6.109e+9 #6_112_000_000 drive_frequency: 4_300_587_281 # 4_401_600_000 #4_541_100_000 @@ -272,7 +269,7 @@ characterization: # parameters for single shot classification threshold: -0.0593 iq_angle: -0.667 - # alpha: 208 MHz + kernel_path: "kernel_q2" 3: readout_frequency: 5_783_000_000 drive_frequency: 4_100_000_000 @@ -281,6 +278,7 @@ characterization: sweetspot: 0.0 mean_gnd_states: [0, 0] mean_exc_states: [0, 0] + kernel_path: "kernel_q3" 4: readout_frequency: 5_515_000_000 drive_frequency: 4_196_800_000 @@ -292,6 +290,7 @@ characterization: # parameters for single shot classification threshold: 0.233806 #0.370954 #0.350665 iq_angle: 0.481 # -91.712 #191.016 + kernel_path: "kernel_q4" coupler: 0: sweetspot: 0.0 From be0c312fc07977865e2d4b80746459d6c415e397 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 17:33:18 +0400 Subject: [PATCH 17/28] Fix kernel_folder path in load_qubits function --- src/qibolab/serialize.py | 15 +++++++++------ tests/dummy_qrc/zurich.py | 4 +++- tests/dummy_qrc/zurich.yml | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 18defb4e27..bd1707951d 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -33,6 +33,11 @@ def load_settings(runcard: dict) -> Settings: return Settings(**runcard["settings"]) +def load_path(runcard: dict) -> Path: + """Load platform settings section from the runcard.""" + return Path(runcard["kernel_folder"]) + + def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: """Load qubits and pairs from the runcard. @@ -43,8 +48,8 @@ def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} if "kernel_folder" in runcard: for qubit in qubits.values(): - qubit.kernel_path = Path( - runcard["kernel_folder"] + runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] + qubit.kernel_path = ( + Path(runcard["kernel_folder"]) / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] ) couplers = {} @@ -115,9 +120,7 @@ def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = No } if kernel_folder: for q in qubits: - characterization["single_qubit"][q]["kernel_path"] = str( - characterization["single_qubit"][q]["kernel_path"] - ).replace(kernel_folder, "") + characterization["single_qubit"][q]["kernel_path"] = characterization["single_qubit"][q]["kernel_path"].name if couplers: characterization["coupler"] = {c.name: {"sweetspot": c.sweetspot} for c in couplers.values()} @@ -156,7 +159,7 @@ def dump_runcard(platform: Platform, path: Path): } if platform.kernel_folder: - settings["kernel_folder"] = platform.kernel_folder + settings["kernel_folder"] = str(platform.kernel_folder) if platform.couplers: settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} diff --git a/tests/dummy_qrc/zurich.py b/tests/dummy_qrc/zurich.py index d7d2a65a24..5b9af29bc5 100644 --- a/tests/dummy_qrc/zurich.py +++ b/tests/dummy_qrc/zurich.py @@ -11,6 +11,7 @@ from qibolab.instruments.zhinst import Zurich from qibolab.serialize import ( load_instrument_settings, + load_path, load_qubits, load_runcard, load_settings, @@ -140,6 +141,7 @@ def create(runcard_path=RUNCARD): runcard = load_runcard(runcard_path) qubits, couplers, pairs = load_qubits(runcard) settings = load_settings(runcard) + kernel_folder = load_path(runcard) # assign channels to qubits and sweetspots(operating points) for q in range(0, 5): @@ -166,5 +168,5 @@ def create(runcard_path=RUNCARD): settings, resonator_type="2D", couplers=couplers, - kernel_folder=KERNEL_FOLDER, + kernel_folder=kernel_folder, ) diff --git a/tests/dummy_qrc/zurich.yml b/tests/dummy_qrc/zurich.yml index e9c8122fb1..8760e92052 100644 --- a/tests/dummy_qrc/zurich.yml +++ b/tests/dummy_qrc/zurich.yml @@ -7,7 +7,7 @@ settings: sampling_rate: 2.e+9 relaxation_time: 300_000 -kernel_folder: "qibolab_platforms_qrc/iqm5q_kernels/" +kernel_folder: "qibolab_platforms_qrc/iqm5q_kernels" instruments: lo_readout: From aed50ebf241bc385ac697c9984c18a4799f4fd52 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Tue, 5 Dec 2023 17:44:59 +0400 Subject: [PATCH 18/28] Fix kernel_folder path in Platform class --- src/qibolab/platform.py | 3 ++- src/qibolab/serialize.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qibolab/platform.py b/src/qibolab/platform.py index 12efb5da2c..739031d235 100644 --- a/src/qibolab/platform.py +++ b/src/qibolab/platform.py @@ -1,6 +1,7 @@ """A platform for executing quantum algorithms.""" from dataclasses import dataclass, field, replace +from pathlib import Path from typing import Dict, List, Optional import networkx as nx @@ -54,7 +55,7 @@ class Platform: couplers: CouplerMap = field(default_factory=dict) """Dictionary mapping coupler names to :class:`qibolab.couplers.Coupler` objects.""" - kernel_folder: Optional[str] = None + kernel_folder: Optional[Path] = None """Folder where each qubit kernels are stored""" is_connected: bool = False diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index bd1707951d..8f889dbcfc 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -5,6 +5,7 @@ example for more details. """ from dataclasses import asdict +from os.path import normcase from pathlib import Path from typing import Tuple @@ -159,7 +160,7 @@ def dump_runcard(platform: Platform, path: Path): } if platform.kernel_folder: - settings["kernel_folder"] = str(platform.kernel_folder) + settings["kernel_folder"] = str(normcase(platform.kernel_folder)) if platform.couplers: settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} From b8a1b6af37e7084b88705086a7758a563eb1c649 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Wed, 6 Dec 2023 10:18:03 +0400 Subject: [PATCH 19/28] Refactor load_qubits function to accept kernel_folder as an optional argument --- src/qibolab/serialize.py | 24 ++++++++---------------- tests/dummy_qrc/zurich.py | 8 ++------ tests/dummy_qrc/zurich.yml | 2 -- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 8f889dbcfc..7f8fd6264e 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -5,7 +5,6 @@ example for more details. """ from dataclasses import asdict -from os.path import normcase from pathlib import Path from typing import Tuple @@ -34,12 +33,7 @@ def load_settings(runcard: dict) -> Settings: return Settings(**runcard["settings"]) -def load_path(runcard: dict) -> Path: - """Load platform settings section from the runcard.""" - return Path(runcard["kernel_folder"]) - - -def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: +def load_qubits(runcard: dict, kernel_folder: Path = None) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: """Load qubits and pairs from the runcard. Uses the native gate and characterization sections of the runcard @@ -47,12 +41,9 @@ def load_qubits(runcard: dict) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: objects. """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} - if "kernel_folder" in runcard: + if kernel_folder is not None: for qubit in qubits.values(): - qubit.kernel_path = ( - Path(runcard["kernel_folder"]) / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] - ) - + qubit.kernel_path = kernel_folder / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] couplers = {} pairs = {} if "coupler" in runcard["characterization"]: @@ -119,9 +110,10 @@ def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = No characterization = { "single_qubit": {q: qubit.characterization for q, qubit in qubits.items()}, } - if kernel_folder: - for q in qubits: + for q in qubits: + if "kernel_path" in characterization["single_qubit"][q]: characterization["single_qubit"][q]["kernel_path"] = characterization["single_qubit"][q]["kernel_path"].name + if couplers: characterization["coupler"] = {c.name: {"sweetspot": c.sweetspot} for c in couplers.values()} @@ -159,8 +151,8 @@ def dump_runcard(platform: Platform, path: Path): "instruments": dump_instruments(platform.instruments), } - if platform.kernel_folder: - settings["kernel_folder"] = str(normcase(platform.kernel_folder)) + print(platform) + if platform.couplers: settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} diff --git a/tests/dummy_qrc/zurich.py b/tests/dummy_qrc/zurich.py index 5b9af29bc5..9a4bf77a3b 100644 --- a/tests/dummy_qrc/zurich.py +++ b/tests/dummy_qrc/zurich.py @@ -11,16 +11,14 @@ from qibolab.instruments.zhinst import Zurich from qibolab.serialize import ( load_instrument_settings, - load_path, load_qubits, load_runcard, load_settings, ) RUNCARD = pathlib.Path(__file__).parent / "zurich.yml" - +KERNEL_FOLDER = pathlib.Path(__file__).parent / "iqm5q_kernels/" N_QUBITS = 5 -KERNEL_FOLDER = "qibolab_platforms_qrc/iqm5q_kernels/" def create(runcard_path=RUNCARD): @@ -139,9 +137,8 @@ def create(runcard_path=RUNCARD): # create qubit objects runcard = load_runcard(runcard_path) - qubits, couplers, pairs = load_qubits(runcard) + qubits, couplers, pairs = load_qubits(runcard, KERNEL_FOLDER) settings = load_settings(runcard) - kernel_folder = load_path(runcard) # assign channels to qubits and sweetspots(operating points) for q in range(0, 5): @@ -168,5 +165,4 @@ def create(runcard_path=RUNCARD): settings, resonator_type="2D", couplers=couplers, - kernel_folder=kernel_folder, ) diff --git a/tests/dummy_qrc/zurich.yml b/tests/dummy_qrc/zurich.yml index 8760e92052..13b893f420 100644 --- a/tests/dummy_qrc/zurich.yml +++ b/tests/dummy_qrc/zurich.yml @@ -7,8 +7,6 @@ settings: sampling_rate: 2.e+9 relaxation_time: 300_000 -kernel_folder: "qibolab_platforms_qrc/iqm5q_kernels" - instruments: lo_readout: frequency: 5_500_000_000 From 8393d1442ec0e6aad606bd92c1d1665877cba297 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Wed, 6 Dec 2023 10:27:14 +0400 Subject: [PATCH 20/28] fix --- src/qibolab/serialize.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 7f8fd6264e..e512845a1f 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -93,7 +93,7 @@ def load_instrument_settings(runcard: dict, instruments: InstrumentMap) -> Instr return instruments -def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = None, kernel_folder: str = None) -> dict: +def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = None) -> dict: """Dump qubit and pair objects to a dictionary following the runcard format.""" native_gates = {"single_qubit": {q: qubit.native_gates.raw for q, qubit in qubits.items()}} @@ -111,8 +111,9 @@ def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = No "single_qubit": {q: qubit.characterization for q, qubit in qubits.items()}, } for q in qubits: - if "kernel_path" in characterization["single_qubit"][q]: - characterization["single_qubit"][q]["kernel_path"] = characterization["single_qubit"][q]["kernel_path"].name + kernel_path = characterization["single_qubit"][q].pop("kernel_path") + if kernel_path is not None: + characterization["single_qubit"][q]["kernel_path"] = kernel_path.name if couplers: characterization["coupler"] = {c.name: {"sweetspot": c.sweetspot} for c in couplers.values()} @@ -157,5 +158,5 @@ def dump_runcard(platform: Platform, path: Path): settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} - settings.update(dump_qubits(platform.qubits, platform.pairs, platform.couplers, platform.kernel_folder)) + settings.update(dump_qubits(platform.qubits, platform.pairs, platform.couplers)) path.write_text(yaml.dump(settings, sort_keys=False, indent=4, default_flow_style=None)) From bc13c8c4ae442c58c9a9e991cda2bb239cf162fa Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Wed, 6 Dec 2023 12:07:24 +0400 Subject: [PATCH 21/28] Update load_qubits function to use extras_folder instead of kernel_folder --- src/qibolab/serialize.py | 6 +++--- tests/dummy_qrc/zurich.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index e512845a1f..979362238c 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -33,7 +33,7 @@ def load_settings(runcard: dict) -> Settings: return Settings(**runcard["settings"]) -def load_qubits(runcard: dict, kernel_folder: Path = None) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: +def load_qubits(runcard: dict, extras_folder: Path = None) -> Tuple[QubitMap, CouplerMap, QubitPairMap]: """Load qubits and pairs from the runcard. Uses the native gate and characterization sections of the runcard @@ -41,9 +41,9 @@ def load_qubits(runcard: dict, kernel_folder: Path = None) -> Tuple[QubitMap, Co objects. """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} - if kernel_folder is not None: + if extras_folder is not None: for qubit in qubits.values(): - qubit.kernel_path = kernel_folder / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] + qubit.kernel_path = extras_folder / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] couplers = {} pairs = {} if "coupler" in runcard["characterization"]: diff --git a/tests/dummy_qrc/zurich.py b/tests/dummy_qrc/zurich.py index 9a4bf77a3b..dfb70700ab 100644 --- a/tests/dummy_qrc/zurich.py +++ b/tests/dummy_qrc/zurich.py @@ -17,7 +17,7 @@ ) RUNCARD = pathlib.Path(__file__).parent / "zurich.yml" -KERNEL_FOLDER = pathlib.Path(__file__).parent / "iqm5q_kernels/" +FOLDER = pathlib.Path(__file__).parent / "iqm5q/" N_QUBITS = 5 @@ -137,7 +137,7 @@ def create(runcard_path=RUNCARD): # create qubit objects runcard = load_runcard(runcard_path) - qubits, couplers, pairs = load_qubits(runcard, KERNEL_FOLDER) + qubits, couplers, pairs = load_qubits(runcard, FOLDER) settings = load_settings(runcard) # assign channels to qubits and sweetspots(operating points) From a71385293d01fd2da2b8e6b827c7c25cdb868800 Mon Sep 17 00:00:00 2001 From: Juan Cereijo Date: Fri, 8 Dec 2023 12:56:29 +0400 Subject: [PATCH 22/28] Update src/qibolab/serialize.py Co-authored-by: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> --- src/qibolab/serialize.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 979362238c..533451abda 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -152,8 +152,6 @@ def dump_runcard(platform: Platform, path: Path): "instruments": dump_instruments(platform.instruments), } - print(platform) - if platform.couplers: settings["couplers"] = list(platform.couplers) settings["topology"] = {coupler: list(pair) for pair, coupler in zip(platform.pairs, platform.couplers)} From 4de2fe49e665548ccb35354a1e30433fc38cf6c9 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Fri, 8 Dec 2023 13:00:00 +0400 Subject: [PATCH 23/28] Comments --- src/qibolab/platform.py | 3 --- src/qibolab/serialize.py | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qibolab/platform.py b/src/qibolab/platform.py index a77f791aa5..770683c64e 100644 --- a/src/qibolab/platform.py +++ b/src/qibolab/platform.py @@ -2,7 +2,6 @@ from collections import defaultdict from dataclasses import dataclass, field, replace -from pathlib import Path from typing import Dict, List, Optional, Tuple import networkx as nx @@ -96,8 +95,6 @@ class Platform: couplers: CouplerMap = field(default_factory=dict) """Dictionary mapping coupler names to :class:`qibolab.couplers.Coupler` objects.""" - kernel_folder: Optional[Path] = None - """Folder where each qubit kernels are stored""" is_connected: bool = False """Flag for whether we are connected to the physical instruments.""" diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 533451abda..77096f465e 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -42,8 +42,9 @@ def load_qubits(runcard: dict, extras_folder: Path = None) -> Tuple[QubitMap, Co """ qubits = {q: Qubit(q, **char) for q, char in runcard["characterization"]["single_qubit"].items()} if extras_folder is not None: + single_qubit = runcard["characterization"]["single_qubit"] for qubit in qubits.values(): - qubit.kernel_path = extras_folder / runcard["characterization"]["single_qubit"][qubit.name]["kernel_path"] + qubit.kernel_path = extras_folder / single_qubit[qubit.name]["kernel_path"] couplers = {} pairs = {} if "coupler" in runcard["characterization"]: From 275b114e873adb5aab662adc15f74da716cbc4d6 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 11 Dec 2023 18:05:06 +0400 Subject: [PATCH 24/28] fix old kernel_path --- src/qibolab/instruments/zhinst.py | 2 +- tests/dummy_qrc/zurich.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 6f3c846c92..dd391e870a 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -436,7 +436,7 @@ def register_readout_line(self, qubit, intermediate_frequency, options): ] if qubit.kernel_path: - self.kernels[q] = qubit.kernel_path / f"kernels_q{q}.npz" + self.kernels[q] = qubit.kernel_path if self.kernels[q].is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( oscillator=None, diff --git a/tests/dummy_qrc/zurich.yml b/tests/dummy_qrc/zurich.yml index 13b893f420..4046262910 100644 --- a/tests/dummy_qrc/zurich.yml +++ b/tests/dummy_qrc/zurich.yml @@ -245,7 +245,7 @@ characterization: # parameters for single shot classification threshold: 0.8836 iq_angle: -1.551 - kernel_path: "kernel_q0" + kernel_path: "kernel_q0.npz" 1: readout_frequency: 4_931_000_000 @@ -255,7 +255,7 @@ characterization: sweetspot: 0.0 mean_gnd_states: [0, 0] mean_exc_states: [0, 0] - kernel_path: "kernel_q1" + kernel_path: "kernel_q1.npz" 2: readout_frequency: 6.109e+9 #6_112_000_000 drive_frequency: 4_300_587_281 # 4_401_600_000 #4_541_100_000 @@ -267,7 +267,7 @@ characterization: # parameters for single shot classification threshold: -0.0593 iq_angle: -0.667 - kernel_path: "kernel_q2" + kernel_path: "kernel_q2.npz" 3: readout_frequency: 5_783_000_000 drive_frequency: 4_100_000_000 @@ -276,7 +276,7 @@ characterization: sweetspot: 0.0 mean_gnd_states: [0, 0] mean_exc_states: [0, 0] - kernel_path: "kernel_q3" + kernel_path: "kernel_q3.npz" 4: readout_frequency: 5_515_000_000 drive_frequency: 4_196_800_000 @@ -288,7 +288,7 @@ characterization: # parameters for single shot classification threshold: 0.233806 #0.370954 #0.350665 iq_angle: 0.481 # -91.712 #191.016 - kernel_path: "kernel_q4" + kernel_path: "kernel_q4.npz" coupler: 0: sweetspot: 0.0 From 585fb5bbf2d3ac066ae8acdaa2c5bb0041edcf14 Mon Sep 17 00:00:00 2001 From: Jacfomg Date: Mon, 11 Dec 2023 18:21:09 +0400 Subject: [PATCH 25/28] simplify code --- src/qibolab/instruments/zhinst.py | 46 ++++++++++++++----------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index dd391e870a..20b64bfc6a 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -437,31 +437,27 @@ def register_readout_line(self, qubit, intermediate_frequency, options): if qubit.kernel_path: self.kernels[q] = qubit.kernel_path - if self.kernels[q].is_file() and options.acquisition_type == AcquisitionType.DISCRIMINATION: - self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( - oscillator=None, - range=qubit.feedback.power_range, - port_delay=self.time_of_flight * NANO_TO_SECONDS, - ) - elif self.kernels[q].is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: - self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( - oscillator=lo.Oscillator( - frequency=intermediate_frequency, - modulation_type=lo.ModulationType.SOFTWARE, - ), - range=qubit.feedback.power_range, - port_delay=self.time_of_flight * NANO_TO_SECONDS, - threshold=qubit.threshold, # To keep compatibility with angle and threshold discrimination - ) - elif not self.kernels[q].is_file() and not options.acquisition_type == AcquisitionType.DISCRIMINATION: - self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( - oscillator=lo.Oscillator( - frequency=intermediate_frequency, - modulation_type=lo.ModulationType.SOFTWARE, - ), - range=qubit.feedback.power_range, - port_delay=self.time_of_flight * NANO_TO_SECONDS, - ) + + oscillator = lo.Oscillator( + frequency=intermediate_frequency, + modulation_type=lo.ModulationType.SOFTWARE, + ) + threshold = None + + if options.acquisition_type == AcquisitionType.DISCRIMINATION: + if self.kernels[q].is_file(): + # Kernels don't work with the software modulation on the acquire signal + oscillator = None + elif not self.kernels[q].is_file(): + # To keep compatibility with angle and threshold discrimination (Remove when possible) + threshold = (qubit.threshold,) + + self.calibration[f"/logical_signal_groups/q{q}/acquire_line"] = lo.SignalCalibration( + oscillator=oscillator, + range=qubit.feedback.power_range, + port_delay=self.time_of_flight * NANO_TO_SECONDS, + threshold=threshold, + ) def register_drive_line(self, qubit, intermediate_frequency): """Registers qubit drive line to calibration and signal map.""" From 85b8bde348e956225aa9dea06ee1deb4845617cc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 21:09:49 +0000 Subject: [PATCH 26/28] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pycqa/isort: 5.12.0 → 5.13.1](https://github.com/pycqa/isort/compare/5.12.0...5.13.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75df67bc71..e52e7e9e8d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: args: - --line-length=120 - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.1 hooks: - id: isort args: ["--profile", "black"] From 406bc663676971cf729c971d160275f6ee91bd28 Mon Sep 17 00:00:00 2001 From: Juan Cereijo Date: Tue, 12 Dec 2023 10:13:01 +0400 Subject: [PATCH 27/28] Update src/qibolab/instruments/zhinst.py Co-authored-by: Alessandro Candido --- src/qibolab/instruments/zhinst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 20b64bfc6a..8582d5d39e 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -448,7 +448,7 @@ def register_readout_line(self, qubit, intermediate_frequency, options): if self.kernels[q].is_file(): # Kernels don't work with the software modulation on the acquire signal oscillator = None - elif not self.kernels[q].is_file(): + else: # To keep compatibility with angle and threshold discrimination (Remove when possible) threshold = (qubit.threshold,) From 337151e73fc0efaf835a9b26b397b2e7f27e6ec4 Mon Sep 17 00:00:00 2001 From: Juan Cereijo Date: Tue, 12 Dec 2023 12:40:50 +0400 Subject: [PATCH 28/28] Update src/qibolab/serialize.py Co-authored-by: Alessandro Candido --- src/qibolab/serialize.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qibolab/serialize.py b/src/qibolab/serialize.py index 77096f465e..0d8b27f7db 100644 --- a/src/qibolab/serialize.py +++ b/src/qibolab/serialize.py @@ -112,9 +112,10 @@ def dump_qubits(qubits: QubitMap, pairs: QubitPairMap, couplers: CouplerMap = No "single_qubit": {q: qubit.characterization for q, qubit in qubits.items()}, } for q in qubits: - kernel_path = characterization["single_qubit"][q].pop("kernel_path") + qubit = characterization["single_qubit"][q] + kernel_path = qubit["kernel_path"] if kernel_path is not None: - characterization["single_qubit"][q]["kernel_path"] = kernel_path.name + qubit["kernel_path"] = kernel_path.name if couplers: characterization["coupler"] = {c.name: {"sweetspot": c.sweetspot} for c in couplers.values()}