From 372348fb34198ec0519654a9d40ad19cc14b643d Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Sun, 31 Mar 2024 15:22:13 +0200 Subject: [PATCH 01/17] feat!: Drop call dunder for platform --- src/qibolab/platform/platform.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index 597c9632a..d19d7f928 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -358,9 +358,6 @@ def sweep( result.update(new_result) return result - def __call__(self, sequence, options): - return self.execute_pulse_sequence(sequence, options) - def get_qubit(self, qubit): """Return the name of the physical qubit corresponding to a logical qubit. From 28d2d33bba979cecf91cce4473c07875c7367436 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Sun, 31 Mar 2024 15:26:06 +0200 Subject: [PATCH 02/17] feat!: Drop single sequence execution for batched one --- src/qibolab/platform/platform.py | 50 ++++++++++---------------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index d19d7f928..3e141e3cf 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -214,40 +214,6 @@ def disconnect(self): instrument.disconnect() self.is_connected = False - def _execute(self, sequence, options, **kwargs): - """Executes sequence on the controllers.""" - result = {} - - for instrument in self.instruments.values(): - if isinstance(instrument, Controller): - new_result = instrument.play( - self.qubits, self.couplers, sequence, options - ) - if isinstance(new_result, dict): - result.update(new_result) - - return result - - def execute_pulse_sequence( - self, sequence: PulseSequence, options: ExecutionParameters, **kwargs - ): - """ - Args: - sequence (:class:`qibolab.pulses.PulseSequence`): Pulse sequences to execute. - options (:class:`qibolab.platforms.platform.ExecutionParameters`): Object holding the execution options. - **kwargs: May need them for something - Returns: - Readout results acquired by after execution. - """ - options = self.settings.fill(options) - - time = ( - (sequence.duration + options.relaxation_time) * options.nshots * NS_TO_SEC - ) - log.info(f"Minimal execution time (sequence): {time}") - - return self._execute(sequence, options, **kwargs) - @property def _controller(self): """Controller instrument used for splitting the unrolled sequences to @@ -264,7 +230,21 @@ def _controller(self): assert len(controllers) == 1 return controllers[0] - def execute_pulse_sequences( + def _execute(self, sequence, options, **kwargs): + """Executes sequence on the controllers.""" + result = {} + + for instrument in self.instruments.values(): + if isinstance(instrument, Controller): + new_result = instrument.play( + self.qubits, self.couplers, sequence, options + ) + if isinstance(new_result, dict): + result.update(new_result) + + return result + + def execute( self, sequences: List[PulseSequence], options: ExecutionParameters, **kwargs ): """ From cf8991aa010fb7bd11f1a919a89ca77e8d4afee3 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Sun, 31 Mar 2024 15:56:17 +0200 Subject: [PATCH 03/17] feat!: Unify batched execution and sweeper interfaces --- src/qibolab/platform/platform.py | 93 ++++++++++++-------------------- 1 file changed, 34 insertions(+), 59 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index 3e141e3cf..6a2f689e5 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -230,14 +230,14 @@ def _controller(self): assert len(controllers) == 1 return controllers[0] - def _execute(self, sequence, options, **kwargs): + def _execute(self, sequence, options, *sweepers, **kwargs): """Executes sequence on the controllers.""" result = {} for instrument in self.instruments.values(): if isinstance(instrument, Controller): new_result = instrument.play( - self.qubits, self.couplers, sequence, options + self.qubits, self.couplers, sequence, options, *sweepers ) if isinstance(new_result, dict): result.update(new_result) @@ -245,9 +245,35 @@ def _execute(self, sequence, options, **kwargs): return result def execute( - self, sequences: List[PulseSequence], options: ExecutionParameters, **kwargs + self, + sequences: List[PulseSequence], + options: ExecutionParameters, + *sweepers: Sweeper, + **kwargs, ): - """ + """Executes a pulse sequences. + + If any sweeper is passed, the execution is performed for the different values of sweeped parameters. + + Example: + .. testcode:: + + import numpy as np + from qibolab.dummy import create_dummy + from qibolab.sweeper import Sweeper, Parameter + from qibolab.pulses import PulseSequence + from qibolab.execution_parameters import ExecutionParameters + + + platform = create_dummy() + sequence = PulseSequence() + parameter = Parameter.frequency + pulse = platform.create_qubit_readout_pulse(qubit=0) + sequence.append(pulse) + parameter_range = np.random.randint(10, size=10) + sweeper = Sweeper(parameter, parameter_range, [pulse]) + platform.execute([sequence], ExecutionParameters(), sweeper) + Args: sequence (List[:class:`qibolab.pulses.PulseSequence`]): Pulse sequences to execute. options (:class:`qibolab.platforms.platform.ExecutionParameters`): Object holding the execution options. @@ -263,7 +289,9 @@ def execute( * options.nshots * NS_TO_SEC ) - log.info(f"Minimal execution time (unrolling): {time}") + for sweep in sweepers: + time *= len(sweep.values) + log.info(f"Minimal execution time: {time}") # find readout pulses ro_pulses = { @@ -276,7 +304,7 @@ def execute( bounds = kwargs.get("bounds", self._controller.bounds) for b in batch(sequences, bounds): sequence, readouts = unroll_sequences(b, options.relaxation_time) - result = self._execute(sequence, options, **kwargs) + result = self._execute(sequence, options, *sweepers, **kwargs) for serial, new_serials in readouts.items(): results[serial].extend(result[ser] for ser in new_serials) @@ -285,59 +313,6 @@ def execute( return results - def sweep( - self, sequence: PulseSequence, options: ExecutionParameters, *sweepers: Sweeper - ): - """Executes a pulse sequence for different values of sweeped - parameters. - - Useful for performing chip characterization. - - Example: - .. testcode:: - - import numpy as np - from qibolab.dummy import create_dummy - from qibolab.sweeper import Sweeper, Parameter - from qibolab.pulses import PulseSequence - from qibolab.execution_parameters import ExecutionParameters - - - platform = create_dummy() - sequence = PulseSequence() - parameter = Parameter.frequency - pulse = platform.create_qubit_readout_pulse(qubit=0) - sequence.append(pulse) - parameter_range = np.random.randint(10, size=10) - sweeper = Sweeper(parameter, parameter_range, [pulse]) - platform.sweep(sequence, ExecutionParameters(), sweeper) - - Returns: - Readout results acquired by after execution. - """ - if options.nshots is None: - options = replace(options, nshots=self.settings.nshots) - - if options.relaxation_time is None: - options = replace(options, relaxation_time=self.settings.relaxation_time) - - time = ( - (sequence.duration + options.relaxation_time) * options.nshots * NS_TO_SEC - ) - for sweep in sweepers: - time *= len(sweep.values) - log.info(f"Minimal execution time (sweep): {time}") - - result = {} - for instrument in self.instruments.values(): - if isinstance(instrument, Controller): - new_result = instrument.sweep( - self.qubits, self.couplers, sequence, options, *sweepers - ) - if isinstance(new_result, dict): - result.update(new_result) - return result - def get_qubit(self, qubit): """Return the name of the physical qubit corresponding to a logical qubit. From 005da4e8c33082eb19e73eeac00a929d9144f5f4 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:01:32 +0200 Subject: [PATCH 04/17] fix: Remove unused kwargs from internal execution --- src/qibolab/platform/platform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index 6a2f689e5..d56f7793d 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -230,7 +230,7 @@ def _controller(self): assert len(controllers) == 1 return controllers[0] - def _execute(self, sequence, options, *sweepers, **kwargs): + def _execute(self, sequence, options, *sweepers): """Executes sequence on the controllers.""" result = {} @@ -304,7 +304,7 @@ def execute( bounds = kwargs.get("bounds", self._controller.bounds) for b in batch(sequences, bounds): sequence, readouts = unroll_sequences(b, options.relaxation_time) - result = self._execute(sequence, options, *sweepers, **kwargs) + result = self._execute(sequence, options, *sweepers) for serial, new_serials in readouts.items(): results[serial].extend(result[ser] for ser in new_serials) From aa8b490e34c3ece76a9fb5135b7cff222d9a7dce Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:03:50 +0200 Subject: [PATCH 05/17] fix: Remove kwargs from exposed execution interface Bounds are now always read from the instrument --- src/qibolab/platform/platform.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index d56f7793d..66bcb2747 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -249,7 +249,6 @@ def execute( sequences: List[PulseSequence], options: ExecutionParameters, *sweepers: Sweeper, - **kwargs, ): """Executes a pulse sequences. @@ -301,8 +300,7 @@ def execute( } results = defaultdict(list) - bounds = kwargs.get("bounds", self._controller.bounds) - for b in batch(sequences, bounds): + for b in batch(sequences, self._controller.bounds): sequence, readouts = unroll_sequences(b, options.relaxation_time) result = self._execute(sequence, options, *sweepers) for serial, new_serials in readouts.items(): From 272c560ebdc1900617c216961d4bfe59826b4165 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:09:19 +0200 Subject: [PATCH 06/17] feat!: Drop sweep from abstract controller interface --- src/qibolab/instruments/abstract.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/qibolab/instruments/abstract.py b/src/qibolab/instruments/abstract.py index bdd44e66c..c42bbdd49 100644 --- a/src/qibolab/instruments/abstract.py +++ b/src/qibolab/instruments/abstract.py @@ -97,17 +97,11 @@ def ports(self, port_name, *args, **kwargs): def play(self, *args, **kwargs): """Play a pulse sequence and retrieve feedback. - Returns: - (Dict[ResultType]) mapping the serial of the readout pulses used to - the acquired :class:`qibolab.result.ExecutionResults` object. - """ - - @abstractmethod - def sweep(self, *args, **kwargs): - """Play a pulse sequence while sweeping one or more parameters. + If :cls:`qibolab.sweeper.Sweeper` objects are passed as arguments, they are + executed in real-time. If not possible, an error is raised. Returns: - (dict) mapping the serial of the readout pulses used to + (Dict[ResultType]) mapping the serial of the readout pulses used to the acquired :class:`qibolab.result.ExecutionResults` object. """ From bd0dfb6d5bd682022b0ed4ab8f79b4815a789aad Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:20:27 +0200 Subject: [PATCH 07/17] docs: Fix results docstrings Removing mentions of no longer existing objects --- src/qibolab/result.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/qibolab/result.py b/src/qibolab/result.py index 837d7fba1..494b74bf5 100644 --- a/src/qibolab/result.py +++ b/src/qibolab/result.py @@ -6,9 +6,7 @@ class IntegratedResults: - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.INTEGRATION and AveragingMode.SINGLESHOT @@ -65,9 +63,7 @@ def average(self): class AveragedIntegratedResults(IntegratedResults): - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.INTEGRATION and AveragingMode.CYCLIC or the averages of ``IntegratedResults`` @@ -99,9 +95,7 @@ def phase(self): class RawWaveformResults(IntegratedResults): - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.RAW and AveragingMode.SINGLESHOT may also be used to store the integration weights ? @@ -109,9 +103,7 @@ class RawWaveformResults(IntegratedResults): class AveragedRawWaveformResults(AveragedIntegratedResults): - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.RAW and AveragingMode.CYCLIC or the averages of ``RawWaveformResults`` @@ -119,9 +111,7 @@ class AveragedRawWaveformResults(AveragedIntegratedResults): class SampleResults: - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.DISCRIMINATION and AveragingMode.SINGLESHOT @@ -156,9 +146,7 @@ def average(self): class AveragedSampleResults(SampleResults): - """Data structure to deal with the output of :func:`qibolab.platforms.abstr - act.AbstractPlatform.execute_pulse_sequence` - :func:`qibolab.platforms.abstract.AbstractPlatform.sweep` + """Data structure to deal with the execution output. Associated with AcquisitionType.DISCRIMINATION and AveragingMode.CYCLIC or the averages of ``SampleResults`` From 840895b805acdc36952d5a294c48ba8201ab0c61 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:22:43 +0200 Subject: [PATCH 08/17] fix: Update platform execution in backend --- src/qibolab/backends.py | 10 ++-------- src/qibolab/platform/platform.py | 9 +++++---- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/qibolab/backends.py b/src/qibolab/backends.py index fc288fb6a..8826351bc 100644 --- a/src/qibolab/backends.py +++ b/src/qibolab/backends.py @@ -102,10 +102,7 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000): if not self.platform.is_connected: self.platform.connect() - readout = self.platform.execute_pulse_sequence( - sequence, - ExecutionParameters(nshots=nshots), - ) + readout = self.platform.execute(sequence, ExecutionParameters(nshots=nshots)) self.platform.disconnect() @@ -147,10 +144,7 @@ def execute_circuits(self, circuits, initial_states=None, nshots=1000): if not self.platform.is_connected: self.platform.connect() - readout = self.platform.execute_pulse_sequences( - sequences, - ExecutionParameters(nshots=nshots), - ) + readout = self.platform.execute(sequences, ExecutionParameters(nshots=nshots)) self.platform.disconnect() diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index 66bcb2747..cd95eb790 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -216,11 +216,12 @@ def disconnect(self): @property def _controller(self): - """Controller instrument used for splitting the unrolled sequences to - batches. + """Identify controller instrument. - Used only by :meth:`qibolab.platform.Platform.execute_pulse_sequences` (unrolling). - This method does not support platforms with more than one controller instruments. + Used for splitting the unrolled sequences to batches. + + This method does not support platforms with more than one + controller instruments. """ controllers = [ instr From 2166b1723a6e1d63c4cd59daeba0b17cdf0abc44 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:25:53 +0200 Subject: [PATCH 09/17] fix: Individual sequence should be passed as a one-element list --- src/qibolab/backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibolab/backends.py b/src/qibolab/backends.py index 8826351bc..72a6fcef5 100644 --- a/src/qibolab/backends.py +++ b/src/qibolab/backends.py @@ -102,7 +102,7 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000): if not self.platform.is_connected: self.platform.connect() - readout = self.platform.execute(sequence, ExecutionParameters(nshots=nshots)) + readout = self.platform.execute([sequence], ExecutionParameters(nshots=nshots)) self.platform.disconnect() From 2593161441e91db80da028b65838feb33fe0dc51 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:30:33 +0200 Subject: [PATCH 10/17] docs: Fix occurrences of execute pulse sequence(s) --- README.md | 2 +- doc/source/main-documentation/qibolab.rst | 19 ++++++++----------- doc/source/tutorials/calibration.rst | 4 ++-- doc/source/tutorials/pulses.rst | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index c2e1bcf88..df04418f4 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ platform.connect() # Execute a pulse sequence options = ExecutionParameters(nshots=1000) -results = platform.execute_pulse_sequence(sequence, options) +results = platform.execute([sequence], options) # Print the acquired shots print(results.samples) diff --git a/doc/source/main-documentation/qibolab.rst b/doc/source/main-documentation/qibolab.rst index 3903108da..91e33d751 100644 --- a/doc/source/main-documentation/qibolab.rst +++ b/doc/source/main-documentation/qibolab.rst @@ -15,7 +15,7 @@ In the platform, the main methods can be divided in different sections: - functions save and change qubit parameters (``dump``, ``update``) - functions to coordinate the instruments (``connect``, ``setup``, ``disconnect``) -- functions to execute experiments (``execute_pulse_sequence``, ``execute_pulse_sequences``, ``sweep``) +- a unique interface to execute experiments (``execute``) - functions to initialize gates (``create_RX90_pulse``, ``create_RX_pulse``, ``create_CZ_pulse``, ``create_MZ_pulse``, ``create_qubit_drive_pulse``, ``create_qubit_readout_pulse``, ``create_RX90_drag_pulse``, ``create_RX_drag_pulse``) - setters and getters of channel/qubit parameters (local oscillator parameters, attenuations, gain and biases) @@ -86,7 +86,7 @@ Now we can execute the sequence on hardware: acquisition_type=AcquisitionType.INTEGRATION, averaging_mode=AveragingMode.CYCLIC, ) - results = platform.execute_pulse_sequence(ps, options=options) + results = platform.execute([ps], options=options) Finally, we can stop instruments and close connections. @@ -390,7 +390,7 @@ When conducting experiments on quantum hardware, pulse sequences are vital. Assu .. testcode:: python - result = platform.execute_pulse_sequence(sequence, options=options) + result = platform.execute([sequence], options=options) Lastly, when conducting an experiment, it is not always required to define a pulse from scratch. Usual pulses, such as pi-pulses or measurements, are already defined in the platform runcard and can be easily initialized with platform methods. @@ -415,7 +415,7 @@ Typical experiments may include both pre-defined pulses and new ones: ) sequence.append(platform.create_MZ_pulse(0)) - results = platform.execute_pulse_sequence(sequence, options=options) + results = platform.execute([sequence], options=options) .. note:: @@ -562,8 +562,7 @@ In the course of several examples, you've encountered the ``options`` argument i .. testcode:: python - res = platform.execute_pulse_sequence(sequence, options=options) - res = platform.sweep(sequence, options=options) + res = platform.execute([sequence], options=options) Let's now delve into the details of the ``options`` parameter and understand its components. @@ -636,7 +635,7 @@ Let's now delve into a typical use case for result objects within the qibolab fr averaging_mode=AveragingMode.CYCLIC, ) - res = platform.execute_pulse_sequence(sequence, options=options) + res = platform.execute([sequence], options=options) The ``res`` object will manifest as a dictionary, mapping the measurement pulse serial to its corresponding results. @@ -734,10 +733,8 @@ Instruments all implement a set of methods: - setup - disconnect -While the controllers, the main instruments in a typical setup, add other two methods: - -- execute_pulse_sequence -- sweep +While the controllers, the main instruments in a typical setup, add another, i.e. +execute. Some more detail on the interal functionalities of instruments is given in :doc:`/tutorials/instrument` diff --git a/doc/source/tutorials/calibration.rst b/doc/source/tutorials/calibration.rst index ba8a2fee6..894e0f862 100644 --- a/doc/source/tutorials/calibration.rst +++ b/doc/source/tutorials/calibration.rst @@ -239,8 +239,8 @@ and its impact on qubit states in the IQ plane. acquisition_type=AcquisitionType.INTEGRATION, ) - results_one = platform.execute_pulse_sequence(one_sequence, options) - results_zero = platform.execute_pulse_sequence(zero_sequence, options) + results_one = platform.execute([one_sequence], options) + results_zero = platform.execute([zero_sequence], options) plt.title("Single shot classification") plt.xlabel("I [a.u.]") diff --git a/doc/source/tutorials/pulses.rst b/doc/source/tutorials/pulses.rst index b3b0b7233..d8ad0e9b5 100644 --- a/doc/source/tutorials/pulses.rst +++ b/doc/source/tutorials/pulses.rst @@ -65,7 +65,7 @@ pulse sequence according to the number of shots ``nshots`` specified. # Executes a pulse sequence. options = ExecutionParameters(nshots=1000, relaxation_time=100) - results = platform.execute_pulse_sequence(sequence, options=options) + results = platform.execut([sequence], options=options) # Disconnect from the instruments platform.disconnect() From 25d96550dddf28dd6e2d98d80cb74294780e9100 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:32:32 +0200 Subject: [PATCH 11/17] fix: Make general sequences execution compatible with individual circuit --- src/qibolab/backends.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qibolab/backends.py b/src/qibolab/backends.py index 72a6fcef5..f3a12394e 100644 --- a/src/qibolab/backends.py +++ b/src/qibolab/backends.py @@ -102,7 +102,10 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000): if not self.platform.is_connected: self.platform.connect() - readout = self.platform.execute([sequence], ExecutionParameters(nshots=nshots)) + readout = self.platform.execute( + [sequence], + ExecutionParameters(nshots=nshots), + )[0] self.platform.disconnect() From 409f402e043cf74f3fab0f6111a00617857b1582 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:39:18 +0200 Subject: [PATCH 12/17] fix: Take the first element within dictionary values --- src/qibolab/backends.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qibolab/backends.py b/src/qibolab/backends.py index f3a12394e..e3016e7b5 100644 --- a/src/qibolab/backends.py +++ b/src/qibolab/backends.py @@ -102,10 +102,11 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000): if not self.platform.is_connected: self.platform.connect() - readout = self.platform.execute( + readout_ = self.platform.execute( [sequence], ExecutionParameters(nshots=nshots), - )[0] + ) + readout = {k: v[0] for k, v in readout_.items()} self.platform.disconnect() From 18afbd79470788c72943356b8b05187dc74d780d Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:42:42 +0200 Subject: [PATCH 13/17] docs: Fix occurrences of execute pulse sequence(s) in examples --- examples/minimum_working_example.py | 2 +- examples/qibolab_v017_1Q_emulator_test_QuTiP.ipynb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/minimum_working_example.py b/examples/minimum_working_example.py index 40ced664c..58c8f367a 100644 --- a/examples/minimum_working_example.py +++ b/examples/minimum_working_example.py @@ -38,7 +38,7 @@ # Connects to lab instruments using the details specified in the calibration settings. platform.connect() # Executes a pulse sequence. -results = platform.execute_pulse_sequence(sequence, nshots=3000) +results = platform.execute([sequence], nshots=3000) print(f"results (amplitude, phase, i, q): {results}") # Disconnect from the instruments platform.disconnect() diff --git a/examples/qibolab_v017_1Q_emulator_test_QuTiP.ipynb b/examples/qibolab_v017_1Q_emulator_test_QuTiP.ipynb index fda85d07b..d72c27c56 100644 --- a/examples/qibolab_v017_1Q_emulator_test_QuTiP.ipynb +++ b/examples/qibolab_v017_1Q_emulator_test_QuTiP.ipynb @@ -108,7 +108,7 @@ "\n", "# Execute the pulse sequence and save the output\n", "options = ExecutionParameters(nshots=1000)\n", - "results = emulator_platform.execute_pulse_sequence(sequence, options=options)" + "results = emulator_platform.execute([sequence], options=options)" ] }, { @@ -454,7 +454,7 @@ "id": "08e1c8ee-8076-47ee-a05a-bcc068d681d0", "metadata": {}, "source": [ - "The simulation results generated by the simulation engine are returned together with the usual outputs of `execute_pulse_sequence` for device platforms and are grouped under 'simulation'. \n", + "The simulation results generated by the simulation engine are returned together with the usual outputs of `execute` for device platforms and are grouped under 'simulation'. \n", "\n", "Let us retrieve the simulation results obtained previously:" ] From 9ce482cf7f95bb33c392fc4d4d8b905a98377d91 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 17:57:28 +0200 Subject: [PATCH 14/17] test: Fix some instrument specific execution calls --- src/qibolab/platform/platform.py | 2 +- tests/test_emulator.py | 36 +++++++++++++++----------------- tests/test_instruments_zhinst.py | 9 +++----- tests/test_result_shapes.py | 9 ++++---- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index cd95eb790..90400cdd7 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -250,7 +250,7 @@ def execute( sequences: List[PulseSequence], options: ExecutionParameters, *sweepers: Sweeper, - ): + ) -> dict[str, list]: """Executes a pulse sequences. If any sweeper is passed, the execution is performed for the different values of sweeped parameters. diff --git a/tests/test_emulator.py b/tests/test_emulator.py index f87a6e014..78612bfba 100644 --- a/tests/test_emulator.py +++ b/tests/test_emulator.py @@ -40,9 +40,7 @@ def test_emulator_initialization(emulators, emulator): "acquisition", [AcquisitionType.DISCRIMINATION, AcquisitionType.INTEGRATION, AcquisitionType.RAW], ) -def test_emulator_execute_pulse_sequence_compute_overlaps( - emulators, emulator, acquisition -): +def test_emulator_execute_compute_overlaps(emulators, emulator, acquisition): nshots = 10 # 100 platform = create_platform(emulator) pulse_simulator = platform.instruments["pulse_simulator"] @@ -54,30 +52,30 @@ def test_emulator_execute_pulse_sequence_compute_overlaps( acquisition is AcquisitionType.DISCRIMINATION or acquisition is AcquisitionType.INTEGRATION ): - results = platform.execute_pulse_sequence(sequence, options) + results = platform.execute([sequence], options) simulated_states = results["simulation"]["output_states"] overlaps = pulse_simulator.simulation_engine.compute_overlaps(simulated_states) if acquisition is AcquisitionType.DISCRIMINATION: - assert results[0].samples.shape == (nshots,) + assert results[0][0].samples.shape == (nshots,) else: - assert results[0].voltage.shape == (nshots,) + assert results[0][0].voltage.shape == (nshots,) else: with pytest.raises(ValueError) as excinfo: - platform.execute_pulse_sequence(sequence, options) + platform.execute(sequence, options) assert "Current emulator does not support requested AcquisitionType" in str( excinfo.value ) @pytest.mark.parametrize("emulator", EMULATORS) -def test_emulator_execute_pulse_sequence_fast_reset(emulators, emulator): +def test_emulator_execute_fast_reset(emulators, emulator): platform = create_platform(emulator) sequence = PulseSequence() sequence.add(platform.create_qubit_readout_pulse(0, 0)) options = ExecutionParameters( nshots=None, fast_reset=True ) # fast_reset does nothing in emulator - result = platform.execute_pulse_sequence(sequence, options) + result = platform.execute([sequence], options) @pytest.mark.parametrize("emulator", EMULATORS) @@ -110,17 +108,17 @@ def test_emulator_single_sweep( ) average = not options.averaging_mode is AveragingMode.SINGLESHOT if parameter in AVAILABLE_SWEEP_PARAMETERS: - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) assert pulse.serial and pulse.qubit in results if average: - results_shape = results[pulse.qubit].statistical_frequency.shape + results_shape = results[pulse.qubit][0].statistical_frequency.shape else: - results_shape = results[pulse.qubit].samples.shape + results_shape = results[pulse.qubit][0].samples.shape assert results_shape == (SWEPT_POINTS,) if average else (nshots, SWEPT_POINTS) else: with pytest.raises(NotImplementedError) as excinfo: - platform.sweep(sequence, options, sweeper) + platform.execute([sequence], options, sweeper) assert "Sweep parameter requested not available" in str(excinfo.value) @@ -171,14 +169,14 @@ def test_emulator_double_sweep_false_history( parameter1 in AVAILABLE_SWEEP_PARAMETERS and parameter2 in AVAILABLE_SWEEP_PARAMETERS ): - results = platform.sweep(sequence, options, sweeper1, sweeper2) + results = platform.execute([sequence], options, sweeper1, sweeper2) assert ro_pulse.serial and ro_pulse.qubit in results if average: - results_shape = results[pulse.qubit].statistical_frequency.shape + results_shape = results[pulse.qubit][0].statistical_frequency.shape else: - results_shape = results[pulse.qubit].samples.shape + results_shape = results[pulse.qubit][0].samples.shape assert ( results_shape == (SWEPT_POINTS, SWEPT_POINTS) @@ -227,14 +225,14 @@ def test_emulator_single_sweep_multiplex( ) average = not options.averaging_mode is AveragingMode.SINGLESHOT if parameter in AVAILABLE_SWEEP_PARAMETERS: - results = platform.sweep(sequence, options, sweeper1) + results = platform.execute([sequence], options, sweeper1) for ro_pulse in ro_pulses.values(): assert ro_pulse.serial and ro_pulse.qubit in results if average: - results_shape = results[ro_pulse.qubit].statistical_frequency.shape + results_shape = results[ro_pulse.qubit][0].statistical_frequency.shape else: - results_shape = results[ro_pulse.qubit].samples.shape + results_shape = results[ro_pulse.qubit][0].samples.shape assert ( results_shape == (SWEPT_POINTS,) if average else (nshots, SWEPT_POINTS) ) diff --git a/tests/test_instruments_zhinst.py b/tests/test_instruments_zhinst.py index ea89655dd..b41be56e6 100644 --- a/tests/test_instruments_zhinst.py +++ b/tests/test_instruments_zhinst.py @@ -892,7 +892,7 @@ def test_connections(instrument): @pytest.mark.qpu -def test_experiment_execute_pulse_sequence_qpu(connected_platform, instrument): +def test_experiment_execute_qpu(connected_platform, instrument): platform = connected_platform sequence = PulseSequence() qubits = {0: platform.qubits[0], "c0": platform.qubits["c0"]} @@ -922,12 +922,9 @@ def test_experiment_execute_pulse_sequence_qpu(connected_platform, instrument): averaging_mode=AveragingMode.CYCLIC, ) - results = platform.execute_pulse_sequence( - sequence, - options, - ) + results = platform.execute([sequence], options) - assert len(results[ro_pulses[q].id]) > 0 + assert len(results[ro_pulses[q][0].id]) > 0 @pytest.mark.qpu diff --git a/tests/test_result_shapes.py b/tests/test_result_shapes.py index d4317689e..487da3091 100644 --- a/tests/test_result_shapes.py +++ b/tests/test_result_shapes.py @@ -2,6 +2,7 @@ import pytest from qibolab import AcquisitionType, AveragingMode, ExecutionParameters +from qibolab.platform.platform import Platform from qibolab.pulses import PulseSequence from qibolab.result import ( AveragedIntegratedResults, @@ -16,7 +17,7 @@ NSWEEP2 = 8 -def execute(platform, acquisition_type, averaging_mode, sweep=False): +def execute(platform: Platform, acquisition_type, averaging_mode, sweep=False): qubit = next(iter(platform.qubits)) qd_pulse = platform.create_RX_pulse(qubit, start=0) @@ -34,10 +35,10 @@ def execute(platform, acquisition_type, averaging_mode, sweep=False): sweeper1 = Sweeper(Parameter.bias, amp_values, qubits=[platform.qubits[qubit]]) # sweeper1 = Sweeper(Parameter.amplitude, amp_values, pulses=[qd_pulse]) sweeper2 = Sweeper(Parameter.frequency, freq_values, pulses=[ro_pulse]) - results = platform.sweep(sequence, options, sweeper1, sweeper2) + results = platform.execute([sequence], options, sweeper1, sweeper2) else: - results = platform.execute_pulse_sequence(sequence, options) - return results[qubit] + results = platform.execute([sequence], options) + return results[qubit][0] @pytest.mark.qpu From 551466c290622604c67b1c9dfc1fa309e4bd23ae Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 18:02:58 +0200 Subject: [PATCH 15/17] test: Fix some execution calls in dummy tests --- src/qibolab/platform/platform.py | 6 ++-- tests/test_dummy.py | 50 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/qibolab/platform/platform.py b/src/qibolab/platform/platform.py index 90400cdd7..3dd122847 100644 --- a/src/qibolab/platform/platform.py +++ b/src/qibolab/platform/platform.py @@ -2,7 +2,7 @@ from collections import defaultdict from dataclasses import dataclass, field, fields -from typing import Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple import networkx as nx from qibo.config import log, raise_error @@ -250,8 +250,8 @@ def execute( sequences: List[PulseSequence], options: ExecutionParameters, *sweepers: Sweeper, - ) -> dict[str, list]: - """Executes a pulse sequences. + ) -> dict[Any, list]: + """Execute a pulse sequences. If any sweeper is passed, the execution is performed for the different values of sweeped parameters. diff --git a/tests/test_dummy.py b/tests/test_dummy.py index 6ff899f78..aef1db640 100644 --- a/tests/test_dummy.py +++ b/tests/test_dummy.py @@ -30,11 +30,11 @@ def test_dummy_execute_pulse_sequence(name, acquisition): sequence.append(platform.create_MZ_pulse(0)) sequence.append(platform.create_RX12_pulse(0)) options = ExecutionParameters(nshots=100, acquisition_type=acquisition) - result = platform.execute_pulse_sequence(sequence, options) + result = platform.execute([sequence], options) if acquisition is AcquisitionType.INTEGRATION: - assert result[0].magnitude.shape == (nshots,) + assert result[0][0].magnitude.shape == (nshots,) elif acquisition is AcquisitionType.RAW: - assert result[0].magnitude.shape == (nshots * ro_pulse.duration,) + assert result[0][0].magnitude.shape == (nshots * ro_pulse.duration,) def test_dummy_execute_coupler_pulse(): @@ -45,7 +45,7 @@ def test_dummy_execute_coupler_pulse(): sequence.append(pulse) options = ExecutionParameters(nshots=None) - result = platform.execute_pulse_sequence(sequence, options) + result = platform.execute([sequence], options) def test_dummy_execute_pulse_sequence_couplers(): @@ -66,7 +66,7 @@ def test_dummy_execute_pulse_sequence_couplers(): sequence.append(platform.create_MZ_pulse(0)) sequence.append(platform.create_MZ_pulse(2)) options = ExecutionParameters(nshots=None) - result = platform.execute_pulse_sequence(sequence, options) + result = platform.execute([sequence], options) @pytest.mark.parametrize("name", PLATFORM_NAMES) @@ -75,7 +75,7 @@ def test_dummy_execute_pulse_sequence_fast_reset(name): sequence = PulseSequence() sequence.append(platform.create_MZ_pulse(0)) options = ExecutionParameters(nshots=None, fast_reset=True) - result = platform.execute_pulse_sequence(sequence, options) + result = platform.execute([sequence], options) @pytest.mark.parametrize("name", PLATFORM_NAMES) @@ -94,7 +94,7 @@ def test_dummy_execute_pulse_sequence_unrolling(name, acquisition, batch_size): for _ in range(nsequences): sequences.append(sequence) options = ExecutionParameters(nshots=nshots, acquisition_type=acquisition) - result = platform.execute_pulse_sequences(sequences, options) + result = platform.execute(sequences, options) assert len(result[0]) == nsequences for r in result[0]: if acquisition is AcquisitionType.INTEGRATION: @@ -117,9 +117,9 @@ def test_dummy_single_sweep_raw(name): averaging_mode=AveragingMode.CYCLIC, acquisition_type=AcquisitionType.RAW, ) - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) assert pulse.id and pulse.qubit in results - shape = results[pulse.qubit].magnitude.shape + shape = results[pulse.qubit][0].magnitude.shape assert shape == (pulse.duration * SWEPT_POINTS,) @@ -162,20 +162,20 @@ def test_dummy_single_sweep_coupler( fast_reset=fast_reset, ) average = not options.averaging_mode is AveragingMode.SINGLESHOT - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) assert ro_pulse.id and ro_pulse.qubit in results if average: results_shape = ( - results[ro_pulse.qubit].magnitude.shape + results[ro_pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[ro_pulse.qubit].statistical_frequency.shape + else results[ro_pulse.qubit][0].statistical_frequency.shape ) else: results_shape = ( - results[ro_pulse.qubit].magnitude.shape + results[ro_pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[ro_pulse.qubit].samples.shape + else results[ro_pulse.qubit][0].samples.shape ) assert results_shape == (SWEPT_POINTS,) if average else (nshots, SWEPT_POINTS) @@ -208,7 +208,7 @@ def test_dummy_single_sweep(name, fast_reset, parameter, average, acquisition, n fast_reset=fast_reset, ) average = not options.averaging_mode is AveragingMode.SINGLESHOT - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) assert pulse.id and pulse.qubit in results if average: @@ -270,21 +270,21 @@ def test_dummy_double_sweep(name, parameter1, parameter2, average, acquisition, acquisition_type=acquisition, ) average = not options.averaging_mode is AveragingMode.SINGLESHOT - results = platform.sweep(sequence, options, sweeper1, sweeper2) + results = platform.execute([sequence], options, sweeper1, sweeper2) assert ro_pulse.id and ro_pulse.qubit in results if average: results_shape = ( - results[pulse.qubit].magnitude.shape + results[pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[pulse.qubit].statistical_frequency.shape + else results[pulse.qubit][0].statistical_frequency.shape ) else: results_shape = ( - results[pulse.qubit].magnitude.shape + results[pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[pulse.qubit].samples.shape + else results[pulse.qubit][0].samples.shape ) assert ( @@ -333,21 +333,21 @@ def test_dummy_single_sweep_multiplex(name, parameter, average, acquisition, nsh acquisition_type=acquisition, ) average = not options.averaging_mode is AveragingMode.SINGLESHOT - results = platform.sweep(sequence, options, sweeper1) + results = platform.execute([sequence], options, sweeper1) for ro_pulse in ro_pulses.values(): assert ro_pulse.id and ro_pulse.qubit in results if average: results_shape = ( - results[ro_pulse.qubit].magnitude.shape + results[ro_pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[ro_pulse.qubit].statistical_frequency.shape + else results[ro_pulse.qubit][0].statistical_frequency.shape ) else: results_shape = ( - results[ro_pulse.qubit].magnitude.shape + results[ro_pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[ro_pulse.qubit].samples.shape + else results[ro_pulse.qubit][0].samples.shape ) assert results_shape == (SWEPT_POINTS,) if average else (nshots, SWEPT_POINTS) From 742b8e4368f9ae463fb81fdd478543fa4caaa665 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 18:08:25 +0200 Subject: [PATCH 16/17] test: Fix dummy tests --- src/qibolab/instruments/dummy.py | 21 --------------------- tests/test_dummy.py | 8 ++++---- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/qibolab/instruments/dummy.py b/src/qibolab/instruments/dummy.py index bdbdda8e5..cc67b56d8 100644 --- a/src/qibolab/instruments/dummy.py +++ b/src/qibolab/instruments/dummy.py @@ -120,27 +120,6 @@ def play( couplers: Dict[QubitId, Coupler], sequence: PulseSequence, options: ExecutionParameters, - ): - exp_points = ( - 1 if options.averaging_mode is AveragingMode.CYCLIC else options.nshots - ) - shape = (exp_points,) - results = {} - - for ro_pulse in sequence.ro_pulses: - values = np.squeeze(self.get_values(options, ro_pulse, shape)) - results[ro_pulse.qubit] = results[ro_pulse.id] = options.results_type( - values - ) - - return results - - def sweep( - self, - qubits: Dict[QubitId, Qubit], - couplers: Dict[QubitId, Coupler], - sequence: PulseSequence, - options: ExecutionParameters, *sweepers: List[Sweeper], ): results = {} diff --git a/tests/test_dummy.py b/tests/test_dummy.py index aef1db640..bff9e914e 100644 --- a/tests/test_dummy.py +++ b/tests/test_dummy.py @@ -213,15 +213,15 @@ def test_dummy_single_sweep(name, fast_reset, parameter, average, acquisition, n assert pulse.id and pulse.qubit in results if average: results_shape = ( - results[pulse.qubit].magnitude.shape + results[pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[pulse.qubit].statistical_frequency.shape + else results[pulse.qubit][0].statistical_frequency.shape ) else: results_shape = ( - results[pulse.qubit].magnitude.shape + results[pulse.qubit][0].magnitude.shape if acquisition is AcquisitionType.INTEGRATION - else results[pulse.qubit].samples.shape + else results[pulse.qubit][0].samples.shape ) assert results_shape == (SWEPT_POINTS,) if average else (nshots, SWEPT_POINTS) From 79b5c14af52b4c2bd282506d5710b3d6feb94ec7 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jul 2024 18:30:06 +0200 Subject: [PATCH 17/17] docs: Fix doctests for unified execution --- doc/source/getting-started/experiment.rst | 4 ++-- doc/source/main-documentation/qibolab.rst | 4 ++-- doc/source/tutorials/calibration.rst | 16 ++++++++-------- doc/source/tutorials/pulses.rst | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/source/getting-started/experiment.rst b/doc/source/getting-started/experiment.rst index 51b7e24f7..6d2751751 100644 --- a/doc/source/getting-started/experiment.rst +++ b/doc/source/getting-started/experiment.rst @@ -208,10 +208,10 @@ We leave to the dedicated tutorial a full explanation of the experiment, but her acquisition_type=AcquisitionType.INTEGRATION, ) - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) # plot the results - amplitudes = results[ro_pulse.id].magnitude + amplitudes = results[ro_pulse.id][0].magnitude frequencies = np.arange(-2e8, +2e8, 1e6) + ro_pulse.frequency plt.title("Resonator Spectroscopy") diff --git a/doc/source/main-documentation/qibolab.rst b/doc/source/main-documentation/qibolab.rst index 91e33d751..50536e71e 100644 --- a/doc/source/main-documentation/qibolab.rst +++ b/doc/source/main-documentation/qibolab.rst @@ -496,7 +496,7 @@ A tipical resonator spectroscopy experiment could be defined with: type=SweeperType.OFFSET, ) - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) .. note:: @@ -543,7 +543,7 @@ For example: type=SweeperType.FACTOR, ) - results = platform.sweep(sequence, options, sweeper_freq, sweeper_amp) + results = platform.execute([sequence], options, sweeper_freq, sweeper_amp) Let's say that the RX pulse has, from the runcard, a frequency of 4.5 GHz and an amplitude of 0.3, the parameter space probed will be: diff --git a/doc/source/tutorials/calibration.rst b/doc/source/tutorials/calibration.rst index 894e0f862..1588ad654 100644 --- a/doc/source/tutorials/calibration.rst +++ b/doc/source/tutorials/calibration.rst @@ -65,7 +65,7 @@ We then define the execution parameters and launch the experiment. acquisition_type=AcquisitionType.INTEGRATION, ) - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) In few seconds, the experiment will be finished and we can proceed to plot it. @@ -73,7 +73,7 @@ In few seconds, the experiment will be finished and we can proceed to plot it. import matplotlib.pyplot as plt - amplitudes = results[readout_pulse.id].magnitude + amplitudes = results[readout_pulse.id][0].magnitude frequencies = np.arange(-2e8, +2e8, 1e6) + readout_pulse.frequency plt.title("Resonator Spectroscopy") @@ -153,9 +153,9 @@ We can now proceed to launch on hardware: acquisition_type=AcquisitionType.INTEGRATION, ) - results = platform.sweep(sequence, options, sweeper) + results = platform.execute([sequence], options, sweeper) - amplitudes = results[readout_pulse.id].magnitude + amplitudes = results[readout_pulse.id][0].magnitude frequencies = np.arange(-2e8, +2e8, 1e6) + drive_pulse.frequency plt.title("Resonator Spectroscopy") @@ -246,13 +246,13 @@ and its impact on qubit states in the IQ plane. plt.xlabel("I [a.u.]") plt.ylabel("Q [a.u.]") plt.scatter( - results_one[readout_pulse1.id].voltage_i, - results_one[readout_pulse1.id].voltage_q, + results_one[readout_pulse1.id][0].voltage_i, + results_one[readout_pulse1.id][0].voltage_q, label="One state", ) plt.scatter( - results_zero[readout_pulse2.id].voltage_i, - results_zero[readout_pulse2.id].voltage_q, + results_zero[readout_pulse2.id][0].voltage_i, + results_zero[readout_pulse2.id][0].voltage_q, label="Zero state", ) plt.show() diff --git a/doc/source/tutorials/pulses.rst b/doc/source/tutorials/pulses.rst index d8ad0e9b5..0b336addf 100644 --- a/doc/source/tutorials/pulses.rst +++ b/doc/source/tutorials/pulses.rst @@ -65,7 +65,7 @@ pulse sequence according to the number of shots ``nshots`` specified. # Executes a pulse sequence. options = ExecutionParameters(nshots=1000, relaxation_time=100) - results = platform.execut([sequence], options=options) + results = platform.execute([sequence], options=options) # Disconnect from the instruments platform.disconnect()