diff --git a/doc/source/main-documentation/qibolab.rst b/doc/source/main-documentation/qibolab.rst index af6cdcc087..9e0e064f85 100644 --- a/doc/source/main-documentation/qibolab.rst +++ b/doc/source/main-documentation/qibolab.rst @@ -249,12 +249,6 @@ Pulses In Qibolab, an extensive API is available for working with pulses and pulse sequences, a fundamental aspect of quantum experiments. At the heart of this API is the :class:`qibolab.pulses.Pulse` object, which empowers users to define and customize pulses with specific parameters. -The API provides specialized subclasses tailored to the main types of pulses typically used in quantum experiments: - -- Readout Pulses (:class:`qibolab.pulses.ReadoutPulse`) -- Drive Pulses (:class:`qibolab.pulses.DrivePulse`) -- Flux Pulses (:class:`qibolab.pulses.FluxPulse`) - Each pulse is associated with a channel and a qubit. Additionally, pulses are defined by a shape, represented by a subclass of :class:`qibolab.pulses.PulseShape`. Qibolab offers a range of pre-defined pulse shapes: @@ -287,13 +281,13 @@ To illustrate, here are some examples of single pulses using the Qibolab API: ) In this way, we defined a rectangular drive pulse using the generic Pulse object. -Alternatively, you can achieve the same result using the dedicated :class:`qibolab.pulses.DrivePulse` object: +Alternatively, you can achieve the same result using the dedicated :class:`qibolab.pulses.Pulse` object: .. testcode:: python - from qibolab.pulses import DrivePulse, Rectangular + from qibolab.pulses import Pulse, Rectangular - pulse = DrivePulse( + pulse = Pulse( start=0, # timing, in all qibolab, is expressed in ns duration=40, amplitude=0.5, # this amplitude is relative to the range of the instrument @@ -314,7 +308,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P sequence = PulseSequence() - pulse1 = DrivePulse( + pulse1 = Pulse( start=0, # timing, in all qibolab, is expressed in ns duration=40, amplitude=0.5, # this amplitude is relative to the range of the instrument @@ -324,7 +318,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P channel="channel", qubit=0, ) - pulse2 = DrivePulse( + pulse2 = Pulse( start=0, # timing, in all qibolab, is expressed in ns duration=40, amplitude=0.5, # this amplitude is relative to the range of the instrument @@ -334,7 +328,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P channel="channel", qubit=0, ) - pulse3 = DrivePulse( + pulse3 = Pulse( start=0, # timing, in all qibolab, is expressed in ns duration=40, amplitude=0.5, # this amplitude is relative to the range of the instrument @@ -344,7 +338,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P channel="channel", qubit=0, ) - pulse4 = DrivePulse( + pulse4 = Pulse( start=0, # timing, in all qibolab, is expressed in ns duration=40, amplitude=0.5, # this amplitude is relative to the range of the instrument @@ -392,7 +386,7 @@ Typical experiments may include both pre-defined pulses and new ones: sequence = PulseSequence() sequence.append(platform.create_RX_pulse(0)) sequence.append( - DrivePulse( + Pulse( start=0, duration=10, amplitude=0.5, diff --git a/doc/source/tutorials/pulses.rst b/doc/source/tutorials/pulses.rst index 6fdab05e1b..1902112503 100644 --- a/doc/source/tutorials/pulses.rst +++ b/doc/source/tutorials/pulses.rst @@ -8,20 +8,14 @@ pulses (:class:`qibolab.pulses.Pulse`) through the .. testcode:: python - from qibolab.pulses import ( - DrivePulse, - ReadoutPulse, - PulseSequence, - Rectangular, - Gaussian, - ) + from qibolab.pulses import Pulse, PulseSequence, PulseType, Rectangular, Gaussian # Define PulseSequence sequence = PulseSequence() # Add some pulses to the pulse sequence sequence.append( - DrivePulse( + Pulse( start=0, frequency=200000000, amplitude=0.3, @@ -32,7 +26,7 @@ pulses (:class:`qibolab.pulses.Pulse`) through the ) ) sequence.append( - ReadoutPulse( + Pulse( start=70, frequency=20000000.0, amplitude=0.5, @@ -40,6 +34,7 @@ pulses (:class:`qibolab.pulses.Pulse`) through the relative_phase=0, shape=Rectangular(), qubit=0, + type=PulseType.READOUT, ) ) diff --git a/examples/pulses_tutorial.ipynb b/examples/pulses_tutorial.ipynb index 696c86b20c..a80241221c 100644 --- a/examples/pulses_tutorial.ipynb +++ b/examples/pulses_tutorial.ipynb @@ -310,29 +310,6 @@ "#### Methods" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pulse implements the following methods:\n", - "- `copy()` returns a deep copy of the object. The later changes to the original do not impact the replica.\n", - "- `shallow_copy()` returns a shallow copy of the object. The replica references to the same `start`, `duration` and `shape` objects.\n", - "The difference in the behaviour of these two methods can be appreciated in the below example:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "p1 = Pulse(0, 40, 0.9, 100e6, 0, Drag(5,1), 0, PulseType.DRIVE)\n", - "p2 = p1.shallow_copy()\n", - "p3 = p1.copy()\n", - "assert p1 == p2\n", - "assert p1 == p3" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/src/qibolab/compilers/compiler.py b/src/qibolab/compilers/compiler.py index 94e0b2bed7..e9403a1c93 100644 --- a/src/qibolab/compilers/compiler.py +++ b/src/qibolab/compilers/compiler.py @@ -14,7 +14,7 @@ u3_rule, z_rule, ) -from qibolab.pulses import PulseSequence, ReadoutPulse +from qibolab.pulses import PulseSequence, PulseType @dataclass @@ -117,7 +117,7 @@ def _compile_gate( # shift start time and phase according to the global sequence for pulse in gate_sequence: pulse.start += start - if not isinstance(pulse, ReadoutPulse): + if pulse.type is not PulseType.READOUT: pulse.relative_phase += virtual_z_phases[pulse.qubit] sequence.append(pulse) diff --git a/src/qibolab/instruments/qblox/cluster_qcm_bb.py b/src/qibolab/instruments/qblox/cluster_qcm_bb.py index 80c37bfa56..9cf433ce1d 100644 --- a/src/qibolab/instruments/qblox/cluster_qcm_bb.py +++ b/src/qibolab/instruments/qblox/cluster_qcm_bb.py @@ -1,5 +1,5 @@ """Qblox Cluster QCM driver.""" - +import copy import json from qblox_instruments.qcodes_drivers.cluster import Cluster as QbloxCluster @@ -349,7 +349,7 @@ def process_pulse_sequence( self._sequencers[port].append(sequencer) # make a temporary copy of the pulses to be processed - pulses_to_be_processed = non_overlapping_pulses.shallow_copy() + pulses_to_be_processed = copy.copy(non_overlapping_pulses) while not pulses_to_be_processed.is_empty: pulse: Pulse = pulses_to_be_processed[0] # attempt to save the waveforms to the sequencer waveforms buffer diff --git a/src/qibolab/instruments/qblox/cluster_qcm_rf.py b/src/qibolab/instruments/qblox/cluster_qcm_rf.py index f11b384675..a66af8fbf3 100644 --- a/src/qibolab/instruments/qblox/cluster_qcm_rf.py +++ b/src/qibolab/instruments/qblox/cluster_qcm_rf.py @@ -1,5 +1,5 @@ """Qblox Cluster QCM-RF driver.""" - +import copy import json from qblox_instruments.qcodes_drivers.cluster import Cluster as QbloxCluster @@ -374,7 +374,7 @@ def process_pulse_sequence( self._sequencers[port].append(sequencer) # make a temporary copy of the pulses to be processed - pulses_to_be_processed = non_overlapping_pulses.shallow_copy() + pulses_to_be_processed = copy.copy(non_overlapping_pulses) while not pulses_to_be_processed.is_empty: pulse: Pulse = pulses_to_be_processed[0] # attempt to save the waveforms to the sequencer waveforms buffer diff --git a/src/qibolab/instruments/qblox/cluster_qrm_rf.py b/src/qibolab/instruments/qblox/cluster_qrm_rf.py index 20da1d58f3..57886a9e78 100644 --- a/src/qibolab/instruments/qblox/cluster_qrm_rf.py +++ b/src/qibolab/instruments/qblox/cluster_qrm_rf.py @@ -1,5 +1,5 @@ """Qblox Cluster QRM-RF driver.""" - +import copy import json import time @@ -434,7 +434,7 @@ def process_pulse_sequence( self._sequencers[port].append(sequencer) # make a temporary copy of the pulses to be processed - pulses_to_be_processed = non_overlapping_pulses.shallow_copy() + pulses_to_be_processed = copy.copy(non_overlapping_pulses) while not pulses_to_be_processed.is_empty: pulse: Pulse = pulses_to_be_processed[0] # attempt to save the waveforms to the sequencer waveforms buffer diff --git a/src/qibolab/instruments/qblox/controller.py b/src/qibolab/instruments/qblox/controller.py index 74809464fd..dd3035d8c1 100644 --- a/src/qibolab/instruments/qblox/controller.py +++ b/src/qibolab/instruments/qblox/controller.py @@ -111,7 +111,7 @@ def _execute_pulse_sequence( sequence: PulseSequence, options: ExecutionParameters, sweepers: list() = [], # list(Sweeper) = [] - **kwargs + **kwargs, # nshots=None, # navgs=None, # relaxation_time=None, diff --git a/src/qibolab/instruments/qblox/sequencer.py b/src/qibolab/instruments/qblox/sequencer.py index 185375185d..db0c068935 100644 --- a/src/qibolab/instruments/qblox/sequencer.py +++ b/src/qibolab/instruments/qblox/sequencer.py @@ -1,3 +1,5 @@ +import copy + import numpy as np from qblox_instruments.qcodes_drivers.sequencer import Sequencer as QbloxSequencer @@ -48,7 +50,7 @@ def add_waveforms( Raises: NotEnoughMemory: If the memory needed to store the waveforms in more than the memory avalible. """ - pulse_copy = pulse.copy() + pulse_copy = copy.deepcopy(pulse) for sweeper in sweepers: if sweeper.pulses and sweeper.parameter == Parameter.amplitude: if pulse in sweeper.pulses: @@ -122,7 +124,7 @@ def bake_pulse_waveforms( """ # In order to generate waveforms for each duration value, the pulse will need to be modified. # To avoid any conflicts, make a copy of the pulse first. - pulse_copy = pulse.copy() + pulse_copy = copy.deepcopy(pulse) # there may be other waveforms stored already, set first index as the next available first_idx = len(self.unique_waveforms) diff --git a/src/qibolab/instruments/zhinst.py b/src/qibolab/instruments/zhinst.py index 05be9f0c82..96d27d2080 100644 --- a/src/qibolab/instruments/zhinst.py +++ b/src/qibolab/instruments/zhinst.py @@ -22,7 +22,7 @@ from qibolab.instruments.abstract import Controller from qibolab.instruments.port import Port from qibolab.instruments.unrolling import batch_max_sequences -from qibolab.pulses import CouplerFluxPulse, FluxPulse, PulseSequence, PulseType +from qibolab.pulses import Pulse, PulseSequence, PulseType from qibolab.qubits import Qubit from qibolab.sweeper import Parameter, Sweeper @@ -235,7 +235,7 @@ def __init__(self, sweeper, qubit=None, sequence=None, pulse=None): # Do something with the pulse coming here if sweeper.parameter is Parameter.bias: if isinstance(qubit, Qubit): - pulse = FluxPulse( + pulse = Pulse.flux( start=0, duration=sequence.duration + sequence.start, amplitude=1, @@ -245,7 +245,7 @@ def __init__(self, sweeper, qubit=None, sequence=None, pulse=None): ) self.signal = f"flux{qubit.name}" if isinstance(qubit, Coupler): - pulse = CouplerFluxPulse( + pulse = Pulse.flux( start=0, duration=sequence.duration + sequence.start, amplitude=1, @@ -253,6 +253,7 @@ def __init__(self, sweeper, qubit=None, sequence=None, pulse=None): channel=qubit.flux.name, qubit=qubit.name, ) + pulse.type = PulseType.COUPLERFLUX self.signal = f"couplerflux{qubit.name}" self.pulse = pulse @@ -664,7 +665,7 @@ def nt_loop(sweeper): for element in aux_list: if pulse == element.pulse: if isinstance(aux_list[aux_list.index(element)], ZhPulse): - if isinstance(pulse, CouplerFluxPulse): + if pulse.type is PulseType.COUPLERFLUX: aux_list[aux_list.index(element)] = ZhSweeper( pulse, sweeper, couplers[pulse.qubit] ) @@ -675,7 +676,7 @@ def nt_loop(sweeper): elif isinstance( aux_list[aux_list.index(element)], ZhSweeper ): - if isinstance(pulse, CouplerFluxPulse): + if pulse.type is PulseType.COUPLERFLUX: aux_list[aux_list.index(element)].add_sweeper( sweeper, couplers[pulse.qubit] ) @@ -1262,7 +1263,7 @@ def sweep_recursion(self, qubits, couplers, exp, exp_calib, exp_options): ) if sweeper.parameter is Parameter.amplitude: for pulse in sweeper.pulses: - pulse = pulse.copy() + pulse = copy.deepcopy(pulse) pulse.amplitude *= max(abs(sweeper.values)) # Proper copy(sweeper) here if we want to keep the sweepers @@ -1325,7 +1326,7 @@ def sweep_recursion_nt(self, qubits, couplers, options, exp, exp_calib): if sweeper.parameter is Parameter.amplitude: for pulse in sweeper.pulses: - pulse = pulse.copy() + pulse = copy.deepcopy(pulse) pulse.amplitude *= max(abs(sweeper.values)) # Proper copy(sweeper) here diff --git a/src/qibolab/native.py b/src/qibolab/native.py index 6f2bcf27d9..8c08595e1e 100644 --- a/src/qibolab/native.py +++ b/src/qibolab/native.py @@ -1,14 +1,9 @@ +import copy from collections import defaultdict from dataclasses import dataclass, field, fields, replace from typing import List, Optional, Union -from qibolab.pulses import ( - CouplerFluxPulse, - FluxPulse, - PulseConstructor, - PulseSequence, - PulseType, -) +from qibolab.pulses import Pulse, PulseSequence, PulseType @dataclass @@ -45,7 +40,7 @@ def from_dict(cls, name, pulse, qubit): qubits (:class:`qibolab.platforms.abstract.Qubit`): Qubit that the pulse is acting on """ - kwargs = pulse.copy() + kwargs = copy.deepcopy(pulse) kwargs["pulse_type"] = PulseType(kwargs.pop("type")) kwargs["qubit"] = qubit return cls(name, **kwargs) @@ -79,7 +74,7 @@ def pulse(self, start, relative_phase=0.0): or :class:`qibolab.pulses.FluxPulse` with the pulse parameters of the gate. """ if self.pulse_type is PulseType.FLUX: - return FluxPulse( + return Pulse.flux( start + self.relative_start, self.duration, self.amplitude, @@ -88,16 +83,16 @@ def pulse(self, start, relative_phase=0.0): qubit=self.qubit.name, ) - pulse_cls = PulseConstructor[self.pulse_type.name].value channel = getattr(self.qubit, self.pulse_type.name.lower()).name - return pulse_cls( + return Pulse( start + self.relative_start, self.duration, self.amplitude, self.frequency, relative_phase, self.shape, - channel, + type=self.pulse_type, + channel=channel, qubit=self.qubit.name, ) @@ -137,7 +132,7 @@ def from_dict(cls, pulse, coupler): coupler (:class:`qibolab.platforms.abstract.Coupler`): Coupler that the pulse is acting on """ - kwargs = pulse.copy() + kwargs = copy.deepcopy(pulse) kwargs["coupler"] = coupler kwargs.pop("type") return cls(**kwargs) @@ -163,11 +158,14 @@ def pulse(self, start): Returns: A :class:`qibolab.pulses.FluxPulse` with the pulse parameters of the gate. """ - return CouplerFluxPulse( + return Pulse( start + self.relative_start, self.duration, self.amplitude, + 0, + 0, self.shape, + type=PulseType.COUPLERFLUX, channel=self.coupler.flux.name, qubit=self.coupler.name, ) @@ -210,7 +208,7 @@ def from_dict(cls, name, sequence, qubits, couplers): sequence = [sequence] for i, pulse in enumerate(sequence): - pulse = pulse.copy() + pulse = copy.deepcopy(pulse) pulse_type = pulse.pop("type") if pulse_type == "coupler": pulse["coupler"] = couplers[pulse.pop("coupler")] diff --git a/src/qibolab/platform.py b/src/qibolab/platform.py index 6f5883b1a6..defed15f8a 100644 --- a/src/qibolab/platform.py +++ b/src/qibolab/platform.py @@ -1,5 +1,5 @@ """A platform for executing quantum algorithms.""" - +import copy from collections import defaultdict from dataclasses import dataclass, field, replace from typing import Dict, List, Optional, Tuple @@ -10,7 +10,7 @@ from qibolab.couplers import Coupler from qibolab.execution_parameters import ExecutionParameters from qibolab.instruments.abstract import Controller, Instrument, InstrumentId -from qibolab.pulses import PulseSequence, ReadoutPulse +from qibolab.pulses import PulseSequence, PulseType from qibolab.qubits import Qubit, QubitId, QubitPair, QubitPairId from qibolab.sweeper import Sweeper @@ -44,10 +44,10 @@ def unroll_sequences( start = 0 for sequence in sequences: for pulse in sequence: - new_pulse = pulse.copy() + new_pulse = copy.deepcopy(pulse) new_pulse.start += start total_sequence.append(new_pulse) - if isinstance(pulse, ReadoutPulse): + if pulse.type is PulseType.READOUT: readout_map[pulse.id].append(new_pulse.id) start = total_sequence.finish + relaxation_time return total_sequence, readout_map diff --git a/src/qibolab/pulses.py b/src/qibolab/pulses.py index 69e2556bea..f1928fcb52 100644 --- a/src/qibolab/pulses.py +++ b/src/qibolab/pulses.py @@ -763,6 +763,12 @@ def __post_init__(self): # TODO: drop the cyclic reference self.shape.pulse = self + @classmethod + def flux(cls, start, duration, amplitude, shape, **kwargs): + return cls( + start, duration, amplitude, 0, 0, shape, type=PulseType.FLUX, **kwargs + ) + @property def finish(self) -> Optional[int]: """Time when the pulse is scheduled to finish.""" @@ -777,6 +783,10 @@ def global_phase(self): This phase is calculated from the pulse start time and frequency as `2 * pi * frequency * start`. """ + if self.type is PulseType.READOUT: + # readout pulses should have zero global phase so that we can + # calculate probabilities in the i-q plane + return 0 # pulse start, duration and finish are in ns return 2 * np.pi * self.frequency * self.start / 1e9 @@ -867,72 +877,11 @@ def __mul__(self, n): raise TypeError(f"Expected int; got {type(n).__name__}") if n < 0: raise TypeError(f"argument n should be >=0, got {n}") - return PulseSequence(*([self.copy()] * n)) + return PulseSequence(*([copy.deepcopy(self)] * n)) def __rmul__(self, n): return self.__mul__(n) - def copy(self): # -> Pulse|ReadoutPulse|DrivePulse|FluxPulse: - """Returns a new Pulse object with the same attributes.""" - - if type(self) == ReadoutPulse: - return ReadoutPulse( - self.start, - self.duration, - self.amplitude, - self.frequency, - self.relative_phase, - repr(self.shape), # self.shape, - self.channel, - self.qubit, - ) - elif type(self) == DrivePulse: - return DrivePulse( - self.start, - self.duration, - self.amplitude, - self.frequency, - self.relative_phase, - repr(self.shape), # self.shape, - self.channel, - self.qubit, - ) - - elif type(self) == FluxPulse: - return FluxPulse( - self.start, - self.duration, - self.amplitude, - self.shape, - self.channel, - self.qubit, - ) - else: - return Pulse( - self.start, - self.duration, - self.amplitude, - self.frequency, - self.relative_phase, - repr(self.shape), # self.shape, - self.channel, - self.type, - self.qubit, - ) - - def shallow_copy(self): # -> Pulse: - return Pulse( - self.start, - self.duration, - self.amplitude, - self.frequency, - self.relative_phase, - self.shape, - self.channel, - self.type, - self.qubit, - ) - def is_equal_ignoring_start(self, item) -> bool: """Check if two pulses are equal ignoring start time.""" return ( @@ -1052,141 +1001,6 @@ def plot(self, savefig_filename=None, sampling_rate=SAMPLING_RATE): plt.close() -class ReadoutPulse(Pulse): - """Describes a readout pulse. - - See - :class: `qibolab.pulses.Pulse` for argument desciption. - """ - - def __init__( - self, - start, - duration, - amplitude, - frequency, - relative_phase, - shape, - channel=0, - qubit=0, - ): - super().__init__( - start, - duration, - amplitude, - frequency, - relative_phase, - shape, - channel, - type=PulseType.READOUT, - qubit=qubit, - ) - - @property - def global_phase(self): - # readout pulses should have zero global phase so that we can - # calculate probabilities in the i-q plane - return 0 - - def copy(self): # -> Pulse|ReadoutPulse|DrivePulse|FluxPulse: - """Returns a new Pulse object with the same attributes.""" - - return ReadoutPulse( - self.start, - self.duration, - self.amplitude, - self.frequency, - self.relative_phase, - copy.deepcopy(self.shape), # self.shape, - self.channel, - self.qubit, - ) - - -class DrivePulse(Pulse): - """Describes a qubit drive pulse. - - See - :class: `qibolab.pulses.Pulse` for argument desciption. - """ - - def __init__( - self, - start, - duration, - amplitude, - frequency, - relative_phase, - shape, - channel=0, - qubit=0, - ): - super().__init__( - start, - duration, - amplitude, - frequency, - relative_phase, - shape, - channel, - type=PulseType.DRIVE, - qubit=qubit, - ) - - -class FluxPulse(Pulse): - """Describes a qubit flux pulse. - - Flux pulses have frequency and relative_phase equal to 0. Their i - and q components are equal. See - :class: `qibolab.pulses.Pulse` for argument desciption. - """ - - PULSE_TYPE = PulseType.FLUX - - def __init__(self, start, duration, amplitude, shape, channel=0, qubit=0): - super().__init__( - start, - duration, - amplitude, - 0, - 0, - shape, - channel, - type=self.PULSE_TYPE, - qubit=qubit, - ) - - def envelope_waveform_q(self, sampling_rate=SAMPLING_RATE) -> Waveform: - """Flux pulses only have i component.""" - return self.shape.envelope_waveform_i(sampling_rate) - - def modulated_waveform_i(self, sampling_rate=SAMPLING_RATE) -> Waveform: - return self.shape.envelope_waveform_i(sampling_rate) - - def modulated_waveform_q(self, sampling_rate=SAMPLING_RATE) -> Waveform: - return self.shape.envelope_waveform_i(sampling_rate) - - -class CouplerFluxPulse(FluxPulse): - """Describes a coupler flux pulse. - - See - :class: `qibolab.pulses.FluxPulse` for argument desciption. - """ - - PULSE_TYPE = PulseType.COUPLERFLUX - - -class PulseConstructor(Enum): - """An enumeration to map each ``PulseType`` to the proper pulse - constructor.""" - - READOUT = ReadoutPulse - DRIVE = DrivePulse - FLUX = FluxPulse - - class PulseSequence(list): """A collection of scheduled pulses. @@ -1261,7 +1075,7 @@ def get_qubit_pulses(self, *qubits): """Return a new sequence containing the pulses on some qubits.""" new_pc = PulseSequence() for pulse in self: - if not isinstance(pulse, CouplerFluxPulse): + if pulse.type is not PulseType.COUPLERFLUX: if pulse.qubit in qubits: new_pc.append(pulse) return new_pc @@ -1270,7 +1084,7 @@ def coupler_pulses(self, *couplers): """Return a new sequence containing the pulses on some couplers.""" new_pc = PulseSequence() for pulse in self: - if isinstance(pulse, CouplerFluxPulse): + if pulse.type is not PulseType.COUPLERFLUX: if pulse.qubit in couplers: new_pc.append(pulse) return new_pc diff --git a/tests/test_dummy.py b/tests/test_dummy.py index 5bb9c0ca4a..74bb4a3fec 100644 --- a/tests/test_dummy.py +++ b/tests/test_dummy.py @@ -2,7 +2,7 @@ import pytest from qibolab import AcquisitionType, AveragingMode, ExecutionParameters, create_platform -from qibolab.pulses import CouplerFluxPulse, PulseSequence +from qibolab.pulses import Pulse, PulseSequence, PulseType from qibolab.qubits import QubitPair from qibolab.sweeper import Parameter, QubitParameter, Sweeper @@ -140,7 +140,7 @@ def test_dummy_single_sweep_coupler( platform = create_platform("dummy_couplers") sequence = PulseSequence() ro_pulse = platform.create_qubit_readout_pulse(qubit=0, start=0) - coupler_pulse = CouplerFluxPulse( + coupler_pulse = Pulse.flux( start=0, duration=40, amplitude=0.5, @@ -148,6 +148,7 @@ def test_dummy_single_sweep_coupler( channel="flux_coupler-0", qubit=0, ) + coupler_pulse.type = PulseType.COUPLERFLUX if parameter is Parameter.amplitude: parameter_range = np.random.rand(SWEPT_POINTS) else: @@ -157,7 +158,6 @@ def test_dummy_single_sweep_coupler( sweeper = Sweeper(parameter, parameter_range, couplers=[platform.couplers[0]]) else: sweeper = Sweeper(parameter, parameter_range, pulses=[coupler_pulse]) - print(sweeper) options = ExecutionParameters( nshots=nshots, averaging_mode=average, diff --git a/tests/test_instruments_qblox_cluster_qcm_bb.py b/tests/test_instruments_qblox_cluster_qcm_bb.py index fb81f7d793..a70680530b 100644 --- a/tests/test_instruments_qblox_cluster_qcm_bb.py +++ b/tests/test_instruments_qblox_cluster_qcm_bb.py @@ -6,7 +6,7 @@ from qibolab.instruments.abstract import Instrument from qibolab.instruments.qblox.cluster_qcm_bb import ClusterQCM_BB from qibolab.instruments.qblox.port import QbloxOutputPort -from qibolab.pulses import FluxPulse, PulseSequence +from qibolab.pulses import PulseSequence from qibolab.sweeper import Parameter, Sweeper, SweeperType from .qblox_fixtures import connected_controller, controller diff --git a/tests/test_instruments_qblox_cluster_qcm_rf.py b/tests/test_instruments_qblox_cluster_qcm_rf.py index f90b6c1c5c..9375599879 100644 --- a/tests/test_instruments_qblox_cluster_qcm_rf.py +++ b/tests/test_instruments_qblox_cluster_qcm_rf.py @@ -4,7 +4,7 @@ from qibolab.instruments.abstract import Instrument from qibolab.instruments.qblox.cluster_qcm_rf import ClusterQCM_RF from qibolab.instruments.qblox.port import QbloxOutputPort -from qibolab.pulses import DrivePulse, PulseSequence +from qibolab.pulses import PulseSequence from qibolab.sweeper import Parameter, Sweeper, SweeperType from .qblox_fixtures import connected_controller, controller diff --git a/tests/test_instruments_qblox_cluster_qrm_rf.py b/tests/test_instruments_qblox_cluster_qrm_rf.py index ff32d772e3..74c2f44c96 100644 --- a/tests/test_instruments_qblox_cluster_qrm_rf.py +++ b/tests/test_instruments_qblox_cluster_qrm_rf.py @@ -4,7 +4,7 @@ from qibolab.instruments.abstract import Instrument from qibolab.instruments.qblox.cluster_qrm_rf import ClusterQRM_RF from qibolab.instruments.qblox.port import QbloxInputPort, QbloxOutputPort -from qibolab.pulses import DrivePulse, PulseSequence, ReadoutPulse +from qibolab.pulses import PulseSequence from qibolab.sweeper import Parameter, Sweeper, SweeperType from .qblox_fixtures import connected_controller, controller diff --git a/tests/test_instruments_qm.py b/tests/test_instruments_qm.py index 73eb6a3dbb..b344e08bf4 100644 --- a/tests/test_instruments_qm.py +++ b/tests/test_instruments_qm.py @@ -8,7 +8,7 @@ from qibolab.instruments.qm import QMOPX, QMPort from qibolab.instruments.qm.acquisition import Acquisition from qibolab.instruments.qm.sequence import BakedPulse, QMPulse, Sequence -from qibolab.pulses import FluxPulse, Pulse, PulseSequence, ReadoutPulse, Rectangular +from qibolab.pulses import Pulse, PulseSequence, PulseType, Rectangular from qibolab.sweeper import Parameter, Sweeper @@ -50,7 +50,17 @@ def test_qmpulse_declare_output(acquisition_type): def test_qmsequence(): qd_pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch0", qubit=0) - ro_pulse = ReadoutPulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) + ro_pulse = Pulse( + 0, + 40, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) qmsequence = Sequence() with pytest.raises(AttributeError): qmsequence.add("test") @@ -76,7 +86,7 @@ def test_qmpulse_previous_and_next(): qmsequence.add(qd_pulse) for qubit in range(nqubits): ro_pulse = QMPulse( - ReadoutPulse( + Pulse( 40, 100, 0.05, @@ -85,6 +95,7 @@ def test_qmpulse_previous_and_next(): Rectangular(), f"readout{qubit}", qubit=qubit, + type=PulseType.READOUT, ) ) ro_qmpulses.append(ro_pulse) @@ -98,7 +109,7 @@ def test_qmpulse_previous_and_next(): def test_qmpulse_previous_and_next_flux(): y90_pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), f"drive1", qubit=1) x_pulse_start = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), f"drive2", qubit=2) - flux_pulse = FluxPulse( + flux_pulse = Pulse.flux( start=y90_pulse.finish, duration=30, amplitude=0.055, @@ -109,11 +120,27 @@ def test_qmpulse_previous_and_next_flux(): theta_pulse = Pulse(70, 40, 0.05, int(3e9), 0.0, Rectangular(), f"drive1", qubit=1) x_pulse_end = Pulse(70, 40, 0.05, int(3e9), 0.0, Rectangular(), f"drive2", qubit=2) - measure_lowfreq = ReadoutPulse( - 110, 100, 0.05, int(3e9), 0.0, Rectangular(), "readout1", qubit=1 + measure_lowfreq = Pulse( + 110, + 100, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "readout1", + qubit=1, + type=PulseType.READOUT, ) - measure_highfreq = ReadoutPulse( - 110, 100, 0.05, int(3e9), 0.0, Rectangular(), "readout2", qubit=2 + measure_highfreq = Pulse( + 110, + 100, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "readout2", + qubit=2, + type=PulseType.READOUT, ) drive11 = QMPulse(y90_pulse) @@ -294,8 +321,13 @@ def test_qmopx_register_flux_pulse(dummy_qrc): qubit = 2 platform = create_platform("qm") opx = platform.instruments["qmopx"] - pulse = FluxPulse( - 0, 30, 0.005, Rectangular(), platform.qubits[qubit].flux.name, qubit + pulse = Pulse.flux( + 0, + 30, + 0.005, + Rectangular(), + channel=platform.qubits[qubit].flux.name, + qubit=qubit, ) target_pulse = { "operation": "control", @@ -315,8 +347,8 @@ def test_qmopx_register_baked_pulse(dummy_qrc, duration): qubit = platform.qubits[3] opx = platform.instruments["qmopx"] opx.config.register_flux_element(qubit) - pulse = FluxPulse( - 3, duration, 0.05, Rectangular(), qubit.flux.name, qubit=qubit.name + pulse = Pulse.flux( + 3, duration, 0.05, Rectangular(), channel=qubit.flux.name, qubit=qubit.name ) qmpulse = BakedPulse(pulse) config = opx.config diff --git a/tests/test_instruments_qmsim.py b/tests/test_instruments_qmsim.py index 7b8726dece..025860990c 100644 --- a/tests/test_instruments_qmsim.py +++ b/tests/test_instruments_qmsim.py @@ -23,7 +23,7 @@ from qibolab import AcquisitionType, AveragingMode, ExecutionParameters, create_platform from qibolab.backends import QibolabBackend from qibolab.instruments.qm import QMSim -from qibolab.pulses import SNZ, FluxPulse, PulseSequence, Rectangular +from qibolab.pulses import SNZ, PulseSequence, Rectangular from qibolab.sweeper import Parameter, Sweeper from .conftest import set_platform_profile diff --git a/tests/test_instruments_zhinst.py b/tests/test_instruments_zhinst.py index d6b5d67568..2a4536a692 100644 --- a/tests/test_instruments_zhinst.py +++ b/tests/test_instruments_zhinst.py @@ -9,13 +9,11 @@ from qibolab.pulses import ( IIR, SNZ, - CouplerFluxPulse, Drag, - FluxPulse, Gaussian, Pulse, PulseSequence, - ReadoutPulse, + PulseType, Rectangular, ) from qibolab.sweeper import Parameter, Sweeper, SweeperType @@ -90,7 +88,17 @@ def test_zhinst_setup(dummy_qrc): def test_zhsequence(dummy_qrc): qd_pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch0", qubit=0) - ro_pulse = ReadoutPulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) + ro_pulse = Pulse( + 0, + 40, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) sequence = PulseSequence() sequence.append(qd_pulse) sequence.append(ro_pulse) @@ -110,8 +118,19 @@ def test_zhsequence(dummy_qrc): def test_zhsequence_couplers(dummy_qrc): qd_pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch0", qubit=0) - ro_pulse = ReadoutPulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) - qc_pulse = CouplerFluxPulse(0, 40, 0.05, Rectangular(), "ch_c0", qubit=3) + ro_pulse = Pulse( + 0, + 40, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) + qc_pulse = Pulse.flux(0, 40, 0.05, Rectangular(), channel="ch_c0", qubit=3) + qc_pulse.type = PulseType.COUPLERFLUX sequence = PulseSequence() sequence.append(qd_pulse) sequence.append(ro_pulse) @@ -132,7 +151,17 @@ def test_zhsequence_couplers(dummy_qrc): def test_zhsequence_couplers_sweeper(dummy_qrc): - ro_pulse = ReadoutPulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) + ro_pulse = Pulse( + 0, + 40, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) sequence = PulseSequence() sequence.append(ro_pulse) IQM5q = create_platform("zurich") @@ -165,9 +194,29 @@ def test_zhsequence_multiple_ro(dummy_qrc): sequence = PulseSequence() qd_pulse = Pulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch0", qubit=0) sequence.append(qd_pulse) - ro_pulse = ReadoutPulse(0, 40, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) + ro_pulse = Pulse( + 0, + 40, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) sequence.append(ro_pulse) - ro_pulse = ReadoutPulse(0, 5000, 0.05, int(3e9), 0.0, Rectangular(), "ch1", qubit=0) + ro_pulse = Pulse( + 0, + 5000, + 0.05, + int(3e9), + 0.0, + Rectangular(), + "ch1", + qubit=0, + type=PulseType.READOUT, + ) sequence.append(ro_pulse) platform = create_platform("zurich") @@ -237,7 +286,7 @@ def test_experiment_execute_pulse_sequence(dummy_qrc): qf_pulses = {} for qubit in qubits.values(): q = qubit.name - qf_pulses[q] = FluxPulse( + qf_pulses[q] = Pulse.flux( start=0, duration=500, amplitude=1, @@ -276,7 +325,7 @@ def test_experiment_execute_pulse_sequence_coupler(dummy_qrc): qf_pulses = {} for qubit in qubits.values(): q = qubit.name - qf_pulses[q] = FluxPulse( + qf_pulses[q] = Pulse.flux( start=0, duration=500, amplitude=1, @@ -291,7 +340,7 @@ def test_experiment_execute_pulse_sequence_coupler(dummy_qrc): cf_pulses = {} for coupler in couplers.values(): c = coupler.name - cf_pulses[c] = CouplerFluxPulse( + cf_pulses[c] = Pulse.flux( start=0, duration=500, amplitude=1, @@ -299,6 +348,7 @@ def test_experiment_execute_pulse_sequence_coupler(dummy_qrc): channel=platform.couplers[c].flux.name, qubit=c, ) + cf_pulses[c].type = PulseType.COUPLERFLUX sequence.append(cf_pulses[c]) options = ExecutionParameters( @@ -366,7 +416,7 @@ def test_experiment_execute_pulse_sequence(dummy_qrc, fast_reset): qubit, start=qd_pulses[qubit].finish ) sequence.append(ro_pulses[qubit]) - qf_pulses[qubit] = FluxPulse( + qf_pulses[qubit] = Pulse.flux( start=0, duration=ro_pulses[qubit].start, amplitude=1, @@ -463,7 +513,7 @@ def test_experiment_sweep_single_coupler(dummy_qrc, parameter1): cf_pulses = {} for coupler in couplers.values(): c = coupler.name - cf_pulses[c] = CouplerFluxPulse( + cf_pulses[c] = Pulse.flux( start=0, duration=500, amplitude=1, @@ -471,6 +521,7 @@ def test_experiment_sweep_single_coupler(dummy_qrc, parameter1): channel=platform.couplers[c].flux.name, qubit=c, ) + cf_pulses[c].type = PulseType.COUPLERFLUX sequence.append(cf_pulses[c]) parameter_range_1 = ( @@ -704,7 +755,7 @@ def test_sim(dummy_qrc): qubit, start=qd_pulses[qubit].finish ) sequence.append(ro_pulses[qubit]) - qf_pulses[qubit] = FluxPulse( + qf_pulses[qubit] = Pulse.flux( start=0, duration=500, amplitude=1, @@ -756,7 +807,7 @@ def test_experiment_execute_pulse_sequence(connected_platform, instrument): qf_pulses = {} for qubit in qubits.values(): q = qubit.name - qf_pulses[q] = FluxPulse( + qf_pulses[q] = Pulse.flux( start=0, duration=500, amplitude=1, diff --git a/tests/test_pulses.py b/tests/test_pulses.py index fd2a686b51..d20a444a73 100644 --- a/tests/test_pulses.py +++ b/tests/test_pulses.py @@ -1,4 +1,5 @@ """Tests ``pulses.py``.""" +import copy import os import pathlib @@ -10,15 +11,12 @@ SNZ, Custom, Drag, - DrivePulse, - FluxPulse, Gaussian, GaussianSquare, Pulse, PulseSequence, PulseShape, PulseType, - ReadoutPulse, Rectangular, ShapeInitError, Waveform, @@ -32,8 +30,10 @@ def test_plot_functions(): p0 = Pulse(0, 40, 0.9, 0, 0, Rectangular(), 0, PulseType.FLUX, 0) p1 = Pulse(0, 40, 0.9, 50e6, 0, Gaussian(5), 0, PulseType.DRIVE, 2) p2 = Pulse(0, 40, 0.9, 50e6, 0, Drag(5, 2), 0, PulseType.DRIVE, 200) - p3 = FluxPulse(0, 40, 0.9, IIR([-0.5, 2], [1], Rectangular()), 0, 200) - p4 = FluxPulse(0, 40, 0.9, SNZ(t_idling=10), 0, 200) + p3 = Pulse.flux( + 0, 40, 0.9, IIR([-0.5, 2], [1], Rectangular()), channel=0, qubit=200 + ) + p4 = Pulse.flux(0, 40, 0.9, SNZ(t_idling=10), channel=0, qubit=200) p5 = Pulse(0, 40, 0.9, 400e6, 0, eCap(alpha=2), 0, PulseType.DRIVE) p6 = Pulse(0, 40, 0.9, 50e6, 0, GaussianSquare(5, 0.9), 0, PulseType.DRIVE, 2) ps = PulseSequence([p0, p1, p2, p3, p4, p5, p6]) @@ -143,8 +143,12 @@ def test_pulse_init(): p7 = Pulse(0, 40, 0.9, 0, 0, Rectangular(), 0, PulseType.FLUX, 0) p8 = Pulse(0, 40, 0.9, 50e6, 0, Gaussian(5), 0, PulseType.DRIVE, 2) p9 = Pulse(0, 40, 0.9, 50e6, 0, Drag(5, 2), 0, PulseType.DRIVE, 200) - p10 = FluxPulse(0, 40, 0.9, IIR([-1, 1], [-0.1, 0.1001], Rectangular()), 0, 200) - p11 = FluxPulse(0, 40, 0.9, SNZ(t_idling=10, b_amplitude=0.5), 0, 200) + p10 = Pulse.flux( + 0, 40, 0.9, IIR([-1, 1], [-0.1, 0.1001], Rectangular()), channel=0, qubit=200 + ) + p11 = Pulse.flux( + 0, 40, 0.9, SNZ(t_idling=10, b_amplitude=0.5), channel=0, qubit=200 + ) p13 = Pulse(0, 40, 0.9, 400e6, 0, eCap(alpha=2), 0, PulseType.DRIVE) p14 = Pulse(0, 40, 0.9, 50e6, 0, GaussianSquare(5, 0.9), 0, PulseType.READOUT, 2) @@ -177,7 +181,6 @@ def test_pulse_attributes(): relative_phase=0.0, shape=Rectangular(), channel=channel, - type=PulseType.READOUT, qubit=qubit, ) @@ -336,27 +339,28 @@ def test_pulse_hash(): t0 = 0 p1 = Pulse(t0, 40, 0.9, 100e6, 0, Drag(5, 1), 0, PulseType.DRIVE) - p2 = p1.shallow_copy() - p3 = p1.copy() + p2 = copy.copy(p1) + p3 = copy.deepcopy(p1) assert p1 == p2 assert p1 == p3 def test_pulse_aliases(): - rop = ReadoutPulse( + rop = Pulse( start=0, duration=50, amplitude=0.9, frequency=20_000_000, relative_phase=0.0, shape=Rectangular(), + type=PulseType.READOUT, channel=0, qubit=0, ) assert rop.start == 0 assert rop.qubit == 0 - dp = DrivePulse( + dp = Pulse( start=0, duration=2000, amplitude=0.9, @@ -369,7 +373,7 @@ def test_pulse_aliases(): assert dp.amplitude == 0.9 assert isinstance(dp.shape, Gaussian) - fp = FluxPulse( + fp = Pulse.flux( start=0, duration=300, amplitude=0.9, shape=Rectangular(), channel=0, qubit=0 ) assert fp.channel == 0 @@ -404,9 +408,9 @@ def test_pulsesequence_init(): def test_pulsesequence_operators(): ps = PulseSequence() - ps += [ReadoutPulse(800, 200, 0.9, 20e6, 0, Rectangular(), 1)] - ps = ps + [ReadoutPulse(800, 200, 0.9, 20e6, 0, Rectangular(), 2)] - ps = [ReadoutPulse(800, 200, 0.9, 20e6, 0, Rectangular(), 3)] + ps + ps += [Pulse(800, 200, 0.9, 20e6, 0, Rectangular(), 1, type=PulseType.READOUT)] + ps = ps + [Pulse(800, 200, 0.9, 20e6, 0, Rectangular(), 2, type=PulseType.READOUT)] + ps = [Pulse(800, 200, 0.9, 20e6, 0, Rectangular(), 3, type=PulseType.READOUT)] + ps p4 = Pulse(100, 40, 0.9, 50e6, 0, Gaussian(5), 3, PulseType.DRIVE) p5 = Pulse(200, 40, 0.9, 50e6, 0, Gaussian(5), 2, PulseType.DRIVE) @@ -455,12 +459,12 @@ def test_pulsesequence_start_finish(): def test_pulsesequence_get_channel_pulses(): - p1 = DrivePulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) - p2 = ReadoutPulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30) - p3 = DrivePulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) - p4 = DrivePulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) - p5 = ReadoutPulse(500, 400, 0.9, 20e6, 0, Rectangular(), 20) - p6 = DrivePulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) + p1 = Pulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) + p2 = Pulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30, type=PulseType.READOUT) + p3 = Pulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) + p4 = Pulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) + p5 = Pulse(500, 400, 0.9, 20e6, 0, Rectangular(), 20, type=PulseType.READOUT) + p6 = Pulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) ps = PulseSequence([p1, p2, p3, p4, p5, p6]) assert ps.channels == [10, 20, 30] @@ -471,13 +475,33 @@ def test_pulsesequence_get_channel_pulses(): def test_pulsesequence_get_qubit_pulses(): - p1 = DrivePulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10, 0) - p2 = ReadoutPulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30, 0) - p3 = DrivePulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20, 1) - p4 = DrivePulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30, 1) - p5 = ReadoutPulse(500, 400, 0.9, 20e6, 0, Rectangular(), 30, 1) - p6 = FluxPulse(600, 400, 0.9, Rectangular(), 40, 1) - p7 = FluxPulse(900, 400, 0.9, Rectangular(), 40, 2) + p1 = Pulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10, qubit=0) + p2 = Pulse( + 100, + 400, + 0.9, + 20e6, + 0, + Rectangular(), + channel=30, + qubit=0, + type=PulseType.READOUT, + ) + p3 = Pulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20, qubit=1) + p4 = Pulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30, qubit=1) + p5 = Pulse( + 500, + 400, + 0.9, + 20e6, + 0, + Rectangular(), + channel=30, + qubit=1, + type=PulseType.READOUT, + ) + p6 = Pulse.flux(600, 400, 0.9, Rectangular(), channel=40, qubit=1) + p7 = Pulse.flux(900, 400, 0.9, Rectangular(), channel=40, qubit=2) ps = PulseSequence([p1, p2, p3, p4, p5, p6, p7]) assert ps.qubits == [0, 1, 2] @@ -488,12 +512,12 @@ def test_pulsesequence_get_qubit_pulses(): def test_pulsesequence_pulses_overlap(): - p1 = DrivePulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) - p2 = ReadoutPulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30) - p3 = DrivePulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) - p4 = DrivePulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) - p5 = ReadoutPulse(500, 400, 0.9, 20e6, 0, Rectangular(), 20) - p6 = DrivePulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) + p1 = Pulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) + p2 = Pulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30, type=PulseType.READOUT) + p3 = Pulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) + p4 = Pulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) + p5 = Pulse(500, 400, 0.9, 20e6, 0, Rectangular(), 20, type=PulseType.READOUT) + p6 = Pulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) ps = PulseSequence([p1, p2, p3, p4, p5, p6]) assert ps.pulses_overlap @@ -503,12 +527,12 @@ def test_pulsesequence_pulses_overlap(): def test_pulsesequence_separate_overlapping_pulses(): - p1 = DrivePulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) - p2 = ReadoutPulse(100, 400, 0.9, 20e6, 0, Rectangular(), 30) - p3 = DrivePulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) - p4 = DrivePulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) - p5 = ReadoutPulse(500, 400, 0.9, 20e6, 0, Rectangular(), 20) - p6 = DrivePulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) + p1 = Pulse(0, 400, 0.9, 20e6, 0, Gaussian(5), 10) + p2 = Pulse(100, 400, 0.9, 20e6, 0, Rectangular(), qubit=30, type=PulseType.READOUT) + p3 = Pulse(300, 400, 0.9, 20e6, 0, Drag(5, 50), 20) + p4 = Pulse(400, 400, 0.9, 20e6, 0, Drag(5, 50), 30) + p5 = Pulse(500, 400, 0.9, 20e6, 0, Rectangular(), qubit=20, type=PulseType.READOUT) + p6 = Pulse(600, 400, 0.9, 20e6, 0, Gaussian(5), 30) ps = PulseSequence([p1, p2, p3, p4, p5, p6]) n = 70 @@ -521,9 +545,18 @@ def test_pulsesequence_separate_overlapping_pulses(): def test_pulse_pulse_order(): t0 = 0 t = 0 - p1 = DrivePulse(t0, 400, 0.9, 20e6, 0, Gaussian(5), 10) - p2 = ReadoutPulse(p1.finish + t, 400, 0.9, 20e6, 0, Rectangular(), 30) - p3 = DrivePulse(p2.finish, 400, 0.9, 20e6, 0, Drag(5, 50), 20) + p1 = Pulse(t0, 400, 0.9, 20e6, 0, Gaussian(5), 10) + p2 = Pulse( + p1.finish + t, + 400, + 0.9, + 20e6, + 0, + Rectangular(), + qubit=30, + type=PulseType.READOUT, + ) + p3 = Pulse(p2.finish, 400, 0.9, 20e6, 0, Drag(5, 50), 20) ps1 = PulseSequence([p1, p2, p3]) ps2 = PulseSequence([p3, p1, p2]) @@ -794,7 +827,7 @@ def test_pulse(): def test_readout_pulse(): duration = 2000 - pulse = ReadoutPulse( + pulse = Pulse( start=0, frequency=200_000_000, amplitude=1, @@ -802,6 +835,7 @@ def test_readout_pulse(): relative_phase=0, shape=f"Rectangular()", channel=11, + type=PulseType.READOUT, ) assert pulse.duration == duration @@ -835,7 +869,7 @@ def test_pulse_sequence_add_readout(): ) sequence.append( - ReadoutPulse( + Pulse( start=128, frequency=20_000_000, amplitude=0.9, @@ -843,6 +877,7 @@ def test_pulse_sequence_add_readout(): relative_phase=0, shape="Rectangular()", channel=11, + type=PulseType.READOUT, ) ) assert len(sequence) == 3