Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace pulse.start with delays and refactor native.py #789

Merged
merged 33 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7a44e99
Drop pulse.serial
alecandido Jan 12, 2024
ed5bdff
Fix QM issues by stringifying pulses ID
alecandido Jan 17, 2024
10419a1
Fix QM tests
alecandido Jan 18, 2024
2f9fb4c
Replace pulse.start with Delay object
stavros11 Jan 29, 2024
f5d234a
refactor: drop unused PulseSequence methods
stavros11 Jan 30, 2024
8bbd1d1
refactor: Simplify native.py
stavros11 Jan 30, 2024
8dd4e31
refactor: Remove pulse.start from platform and sweeper
stavros11 Jan 30, 2024
17bee7e
refactor: stop using create_* in default compiler
stavros11 Feb 23, 2024
daa18d2
fix: remove pulse.start from compiler
stavros11 Feb 23, 2024
66cfb84
fix: remove relative_start from dummy_qrc runcards
stavros11 Feb 23, 2024
279454e
fix: remove relative_start from dummy
stavros11 Feb 23, 2024
7959c91
fix: pylint
stavros11 Feb 23, 2024
c052e01
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 30, 2024
1a36a8b
chore: remove phase from dummy runcards
stavros11 Mar 1, 2024
98a5f19
chore: remove phase from dummy platform
stavros11 Mar 1, 2024
02ce125
chore: remove phase from dummy platform
stavros11 Mar 1, 2024
f434d7e
test: first batch of fixing tests
stavros11 Mar 1, 2024
2e07f87
test: fix pulse tests
stavros11 Mar 1, 2024
5a8f00d
chore: fix pylint
stavros11 Mar 1, 2024
9fe83b7
docs: update and fix doctests
stavros11 Mar 1, 2024
17f5822
feat: Add VirtualZ pulse
stavros11 Mar 4, 2024
8a04f6d
fix: platform serialization test
stavros11 Mar 4, 2024
8d5caf2
test: remove negative drag from test runcards (see #826)
stavros11 Mar 4, 2024
c13a301
fix: compiler and tests
stavros11 Mar 4, 2024
35e6d93
Fix Zurich tests
alecandido Jan 18, 2024
469b8f0
test: fix conflicts in tests
stavros11 Feb 21, 2024
6e612dc
fix: tests after merging (compiler tests still failing)
stavros11 Mar 21, 2024
a3b9f60
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 21, 2024
682b1e4
fix: compiler tests
stavros11 Mar 21, 2024
39a175c
refactor: simplify compiler rules
stavros11 Mar 21, 2024
ad12612
refactor: native two qubit to empty PulseSequence
stavros11 Mar 21, 2024
2f1f112
fix: doctest
stavros11 Mar 21, 2024
3921bef
refactor: remove clock from unrolling
stavros11 Mar 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,36 @@ A simple example on how to connect to a platform and use it execute a pulse sequ

```python
from qibolab import create_platform, ExecutionParameters
from qibolab.pulses import DrivePulse, ReadoutPulse, PulseSequence
from qibolab.pulses import Pulse, Delay, PulseType

# Define PulseSequence
sequence = PulseSequence()
# Add some pulses to the pulse sequence
sequence.add(
DrivePulse(
start=0,
sequence.append(
Pulse(
amplitude=0.3,
duration=4000,
frequency=200_000_000,
relative_phase=0,
shape="Gaussian(5)", # Gaussian shape with std = duration / 5
type=PulseType.DRIVE,
channel=1,
)
)

sequence.add(
sequence.append(
Delay(
duration=4000,
channel=2,
)
)
sequence.append(
ReadoutPulse(
start=4004,
amplitude=0.9,
duration=2000,
frequency=20_000_000,
relative_phase=0,
shape="Rectangular",
type=PulseType.READOUT,
channel=2,
)
)
Expand Down
6 changes: 1 addition & 5 deletions doc/source/getting-started/experiment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,13 @@ And the we can define the runcard ``my_platform/parameters.json``:
"frequency": 5500000000,
"shape": "Gaussian(3)",
"type": "qd",
"start": 0,
"phase": 0
},
"MZ": {
"duration": 2000,
"amplitude": 0.02,
"frequency": 7370000000,
"shape": "Rectangular()",
"type": "ro",
"start": 0,
"phase": 0
}
}
},
Expand Down Expand Up @@ -193,7 +189,7 @@ We leave to the dedicated tutorial a full explanation of the experiment, but her

# define the pulse sequence
sequence = PulseSequence()
ro_pulse = platform.create_MZ_pulse(qubit=0, start=0)
ro_pulse = platform.create_MZ_pulse(qubit=0)
sequence.append(ro_pulse)

# define a sweeper for a frequency scan
Expand Down
57 changes: 22 additions & 35 deletions doc/source/main-documentation/qibolab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ Now we can create a simple sequence (again, without explicitly giving any qubit

.. testcode:: python

from qibolab.pulses import PulseSequence
from qibolab.pulses import PulseSequence, Delay

ps = PulseSequence()
ps.append(platform.create_RX_pulse(qubit=0, start=0)) # start time is in ns
ps.append(platform.create_RX_pulse(qubit=0, start=100))
ps.append(platform.create_MZ_pulse(qubit=0, start=200))
ps.append(platform.create_RX_pulse(qubit=0))
ps.append(platform.create_RX_pulse(qubit=0))
alecandido marked this conversation as resolved.
Show resolved Hide resolved
ps.append(Delay(200, platform.qubits[0].readout.name))
ps.append(platform.create_MZ_pulse(qubit=0))

Now we can execute the sequence on hardware:

Expand Down Expand Up @@ -269,7 +270,6 @@ To illustrate, here are some examples of single pulses using the Qibolab API:
from qibolab.pulses import Pulse, Rectangular

pulse = Pulse(
start=0, # Timing, always in nanoseconds (ns)
duration=40, # Pulse duration in ns
amplitude=0.5, # Amplitude relative to instrument range
frequency=1e8, # Frequency in Hz
Expand All @@ -288,8 +288,7 @@ Alternatively, you can achieve the same result using the dedicated :class:`qibol
from qibolab.pulses import Pulse, Rectangular

pulse = Pulse(
start=0, # timing, in all qibolab, is expressed in ns
duration=40,
duration=40, # timing, in all qibolab, is expressed in ns
amplitude=0.5, # this amplitude is relative to the range of the instrument
frequency=1e8, # frequency are in Hz
relative_phase=0, # phases are in radians
Expand All @@ -309,8 +308,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P
sequence = PulseSequence()

pulse1 = Pulse(
start=0, # timing, in all qibolab, is expressed in ns
duration=40,
duration=40, # timing, in all qibolab, is expressed in ns
amplitude=0.5, # this amplitude is relative to the range of the instrument
frequency=1e8, # frequency are in Hz
relative_phase=0, # phases are in radians
Expand All @@ -319,8 +317,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P
qubit=0,
)
pulse2 = Pulse(
start=0, # timing, in all qibolab, is expressed in ns
duration=40,
duration=40, # timing, in all qibolab, is expressed in ns
amplitude=0.5, # this amplitude is relative to the range of the instrument
frequency=1e8, # frequency are in Hz
relative_phase=0, # phases are in radians
Expand All @@ -329,8 +326,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P
qubit=0,
)
pulse3 = Pulse(
start=0, # timing, in all qibolab, is expressed in ns
duration=40,
duration=40, # timing, in all qibolab, is expressed in ns
amplitude=0.5, # this amplitude is relative to the range of the instrument
frequency=1e8, # frequency are in Hz
relative_phase=0, # phases are in radians
Expand All @@ -339,8 +335,7 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P
qubit=0,
)
pulse4 = Pulse(
start=0, # timing, in all qibolab, is expressed in ns
duration=40,
duration=40, # timing, in all qibolab, is expressed in ns
amplitude=0.5, # this amplitude is relative to the range of the instrument
frequency=1e8, # frequency are in Hz
relative_phase=0, # phases are in radians
Expand All @@ -361,12 +356,9 @@ To organize pulses into sequences, Qibolab provides the :class:`qibolab.pulses.P
.. testoutput:: python
:hide:

Total duration: 40
Total duration: 160
We have 0 pulses on channel 1.

.. warning::

Pulses in PulseSequences are ordered automatically following the start time (and the channel if needed). Not by the definition order.

When conducting experiments on quantum hardware, pulse sequences are vital. Assuming you have already initialized a platform, executing an experiment is as simple as:

Expand All @@ -387,7 +379,6 @@ Typical experiments may include both pre-defined pulses and new ones:
sequence.append(platform.create_RX_pulse(0))
sequence.append(
Pulse(
start=0,
duration=10,
amplitude=0.5,
frequency=2500000000,
Expand All @@ -396,7 +387,7 @@ Typical experiments may include both pre-defined pulses and new ones:
channel="0",
)
)
sequence.append(platform.create_MZ_pulse(0, start=0))
sequence.append(platform.create_MZ_pulse(0))

results = platform.execute_pulse_sequence(sequence, options=options)

Expand Down Expand Up @@ -468,15 +459,9 @@ A tipical resonator spectroscopy experiment could be defined with:
from qibolab.sweeper import Parameter, Sweeper, SweeperType

sequence = PulseSequence()
sequence.append(
platform.create_MZ_pulse(0, start=0)
) # readout pulse for qubit 0 at 4 GHz
sequence.append(
platform.create_MZ_pulse(1, start=0)
) # readout pulse for qubit 1 at 5 GHz
sequence.append(
platform.create_MZ_pulse(2, start=0)
) # readout pulse for qubit 2 at 6 GHz
sequence.append(platform.create_MZ_pulse(0)) # readout pulse for qubit 0 at 4 GHz
sequence.append(platform.create_MZ_pulse(1)) # readout pulse for qubit 1 at 5 GHz
sequence.append(platform.create_MZ_pulse(2)) # readout pulse for qubit 2 at 6 GHz

sweeper = Sweeper(
parameter=Parameter.frequency,
Expand Down Expand Up @@ -509,10 +494,13 @@ For example:

.. testcode:: python

from qibolab.pulses import PulseSequence, Delay
stavros11 marked this conversation as resolved.
Show resolved Hide resolved

sequence = PulseSequence()

sequence.append(platform.create_RX_pulse(0))
sequence.append(platform.create_MZ_pulse(0, start=sequence[0].finish))
sequence.append(Delay(sequence.duration, platform.qubits[0].readout.name))
sequence.append(platform.create_MZ_pulse(0))

sweeper_freq = Sweeper(
parameter=Parameter.frequency,
Expand Down Expand Up @@ -605,8 +593,8 @@ Let's now delve into a typical use case for result objects within the qibolab fr

.. testcode:: python

drive_pulse_1 = platform.create_MZ_pulse(0, start=0)
measurement_pulse = platform.create_qubit_readout_pulse(0, start=0)
drive_pulse_1 = platform.create_RX_pulse(0)
measurement_pulse = platform.create_MZ_pulse(0)

sequence = PulseSequence()
sequence.append(drive_pulse_1)
Expand Down Expand Up @@ -683,7 +671,7 @@ If this set is universal any circuit can be transpiled and compiled to a pulse s
Every :class:`qibolab.qubits.Qubit` object contains a :class:`qibolab.native.SingleQubitNatives` object which holds the parameters of its native single-qubit gates,
while each :class:`qibolab.qubits.QubitPair` objects contains a :class:`qibolab.native.TwoQubitNatives` object which holds the parameters of the native two-qubit gates acting on the pair.

Each native gate is represented by a :class:`qibolab.native.NativePulse` or :class:`qibolab.native.NativeSequence` which contain all the calibrated parameters and can be converted to an actual :class:`qibolab.pulses.PulseSequence` that is then executed in the platform.
Each native gate is represented by a :class:`qibolab.pulses.Pulse` or :class:`qibolab.pulses.PulseSequence` which contain all the calibrated parameters.
Typical single-qubit native gates are the Pauli-X gate, implemented via a pi-pulse which is calibrated using Rabi oscillations and the measurement gate, implemented via a pulse sent in the readout line followed by an acquisition.
For a universal set of single-qubit gates, the RX90 (pi/2-pulse) gate is required, which is implemented by halving the amplitude of the calibrated pi-pulse.
U3, the most general single-qubit gate can be implemented using two RX90 pi-pulses and some virtual Z-phases which are included in the phase of later pulses.
Expand Down Expand Up @@ -739,7 +727,6 @@ The most important instruments are the controller, the following is a table of t
"RTS frequency", "yes","yes","yes","yes"
"RTS amplitude", "yes","yes","yes","yes"
"RTS duration", "yes","yes","yes","yes"
"RTS start", "yes","yes","yes","yes"
"RTS relative phase", "yes","yes","yes","yes"
"RTS 2D any combination", "yes","yes","yes","yes"
"Sequence unrolling", "dev","dev","dev","dev"
Expand Down
18 changes: 10 additions & 8 deletions doc/source/tutorials/calibration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ around the pre-defined frequency.

# create pulse sequence and add pulse
sequence = PulseSequence()
readout_pulse = platform.create_MZ_pulse(qubit=0, start=0)
readout_pulse = platform.create_MZ_pulse(qubit=0)
sequence.append(readout_pulse)

# allocate frequency sweeper
Expand Down Expand Up @@ -110,7 +110,7 @@ complex pulse sequence. Therefore with start with that:
import numpy as np
import matplotlib.pyplot as plt
from qibolab import create_platform
from qibolab.pulses import PulseSequence
from qibolab.pulses import PulseSequence, Delay
from qibolab.sweeper import Sweeper, SweeperType, Parameter
from qibolab.execution_parameters import (
ExecutionParameters,
Expand All @@ -123,11 +123,12 @@ complex pulse sequence. Therefore with start with that:

# create pulse sequence and add pulses
sequence = PulseSequence()
drive_pulse = platform.create_RX_pulse(qubit=0, start=0)
drive_pulse = platform.create_RX_pulse(qubit=0)
drive_pulse.duration = 2000
drive_pulse.amplitude = 0.01
readout_pulse = platform.create_MZ_pulse(qubit=0, start=drive_pulse.finish)
readout_pulse = platform.create_MZ_pulse(qubit=0)
sequence.append(drive_pulse)
sequence.append(Delay(drive_pulse.duration, readout_pulse.channel))
sequence.append(readout_pulse)

# allocate frequency sweeper
Expand Down Expand Up @@ -205,7 +206,7 @@ and its impact on qubit states in the IQ plane.
import numpy as np
import matplotlib.pyplot as plt
from qibolab import create_platform
from qibolab.pulses import PulseSequence
from qibolab.pulses import PulseSequence, Delay
from qibolab.sweeper import Sweeper, SweeperType, Parameter
from qibolab.execution_parameters import (
ExecutionParameters,
Expand All @@ -218,14 +219,15 @@ and its impact on qubit states in the IQ plane.

# create pulse sequence 1 and add pulses
one_sequence = PulseSequence()
drive_pulse = platform.create_RX_pulse(qubit=0, start=0)
readout_pulse1 = platform.create_MZ_pulse(qubit=0, start=drive_pulse.finish)
drive_pulse = platform.create_RX_pulse(qubit=0)
readout_pulse1 = platform.create_MZ_pulse(qubit=0)
one_sequence.append(drive_pulse)
one_sequence.append(Delay(drive_pulse.duration, readout_pulse1.channel))
one_sequence.append(readout_pulse1)

# create pulse sequence 2 and add pulses
zero_sequence = PulseSequence()
readout_pulse2 = platform.create_MZ_pulse(qubit=0, start=0)
readout_pulse2 = platform.create_MZ_pulse(qubit=0)
zero_sequence.append(readout_pulse2)

options = ExecutionParameters(
Expand Down
9 changes: 2 additions & 7 deletions doc/source/tutorials/compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,14 @@ The following example shows how to modify the transpiler and compiler in order t


# define a compiler rule that translates X to the pi-pulse
def x_rule(gate, platform):
def x_rule(gate, qubit):
"""X gate applied with a single pi-pulse."""
qubit = gate.target_qubits[0]
sequence = PulseSequence()
sequence.append(platform.create_RX_pulse(qubit, start=0))
return sequence, {}
return PulseSequence([qubit.native_gates.RX])


# the empty dictionary is needed because the X gate does not require any virtual Z-phases

backend = QibolabBackend(platform="dummy")
# disable the transpiler
backend.transpiler = None
# register the new X rule in the compiler
backend.compiler[gates.X] = x_rule

Expand Down
Loading
Loading