Skip to content

Commit

Permalink
Merge pull request #767 from qiboteam/simplify-pulse-5
Browse files Browse the repository at this point in the history
Drop Pulse subclasses
  • Loading branch information
alecandido authored Jan 22, 2024
2 parents bf8232d + f10ba3a commit 4cf8b6b
Show file tree
Hide file tree
Showing 21 changed files with 262 additions and 363 deletions.
22 changes: 8 additions & 14 deletions doc/source/main-documentation/qibolab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down
13 changes: 4 additions & 9 deletions doc/source/tutorials/pulses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -32,14 +26,15 @@ pulses (:class:`qibolab.pulses.Pulse`) through the
)
)
sequence.append(
ReadoutPulse(
Pulse(
start=70,
frequency=20000000.0,
amplitude=0.5,
duration=3000,
relative_phase=0,
shape=Rectangular(),
qubit=0,
type=PulseType.READOUT,
)
)

Expand Down
23 changes: 0 additions & 23 deletions examples/pulses_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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": {},
Expand Down
4 changes: 2 additions & 2 deletions src/qibolab/compilers/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
u3_rule,
z_rule,
)
from qibolab.pulses import PulseSequence, ReadoutPulse
from qibolab.pulses import PulseSequence, PulseType


@dataclass
Expand Down Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions src/qibolab/instruments/qblox/cluster_qcm_bb.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Qblox Cluster QCM driver."""

import copy
import json

from qblox_instruments.qcodes_drivers.cluster import Cluster as QbloxCluster
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/qibolab/instruments/qblox/cluster_qcm_rf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Qblox Cluster QCM-RF driver."""

import copy
import json

from qblox_instruments.qcodes_drivers.cluster import Cluster as QbloxCluster
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/qibolab/instruments/qblox/cluster_qrm_rf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Qblox Cluster QRM-RF driver."""

import copy
import json
import time

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/qibolab/instruments/qblox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions src/qibolab/instruments/qblox/sequencer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import copy

import numpy as np
from qblox_instruments.qcodes_drivers.sequencer import Sequencer as QbloxSequencer

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
15 changes: 8 additions & 7 deletions src/qibolab/instruments/zhinst.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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,
Expand All @@ -245,14 +245,15 @@ 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,
shape="Rectangular",
channel=qubit.flux.name,
qubit=qubit.name,
)
pulse.type = PulseType.COUPLERFLUX
self.signal = f"couplerflux{qubit.name}"

self.pulse = pulse
Expand Down Expand Up @@ -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]
)
Expand All @@ -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]
)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 4cf8b6b

Please sign in to comment.