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

RX90 calibration implementation #1044

Open
wants to merge 69 commits into
base: 0.2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
14f80b4
first test for swittching from pi to pi-half
ElStabilini Nov 19, 2024
ec4b7ad
fixed pi half calibration sequence
ElStabilini Nov 20, 2024
9f63c69
modified classes and methods for running rabi for RX90
ElStabilini Nov 20, 2024
33db217
added option to save duration of RX90 pulse
ElStabilini Nov 21, 2024
32cceda
started modifying rabi ef for using RX90
ElStabilini Nov 21, 2024
7661361
modified pihalf_pulse to rx90 in parameters
ElStabilini Nov 21, 2024
d03f383
Update rabi.rst
ElStabilini Nov 21, 2024
d0c1228
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 21, 2024
e6a2395
set pi calibration as default and change rx90 dtype
ElStabilini Nov 21, 2024
144f468
Saving modified documentation
ElStabilini Nov 21, 2024
c112748
fix ordering error
ElStabilini Nov 21, 2024
f083434
moved all pihalf_pulses in Rabi-Data class
ElStabilini Nov 21, 2024
f52765f
moved all pihalf_pulses in Rabi-Data class
ElStabilini Nov 21, 2024
efcb55a
fixed errors
ElStabilini Nov 21, 2024
66f0b71
Update rabi.rst
ElStabilini Nov 21, 2024
1f16f50
fixed amplitude_sequence and length_sequence inputs
ElStabilini Nov 21, 2024
f8e9021
Sync remote and local branches
ElStabilini Nov 21, 2024
a08cf3c
fixed acquisition error
ElStabilini Nov 21, 2024
0f9ec82
fixed error
ElStabilini Nov 21, 2024
6111a46
fix rabi length signal
ElStabilini Nov 22, 2024
973b318
fix rabi length signal
ElStabilini Nov 22, 2024
3164fd8
align True
ElStabilini Nov 22, 2024
393d039
Update rabi.rst
ElStabilini Nov 22, 2024
1742dc1
Add rabi_amplitude_rx90
ElStabilini Nov 22, 2024
30dd98c
Update rabi.rst
ElStabilini Nov 22, 2024
f521abc
rename pi_half to rx90
ElStabilini Nov 22, 2024
bf70bf6
Sync local and remote branches
ElStabilini Nov 22, 2024
349e312
force ef rabi protocol with pihalf
ElStabilini Nov 22, 2024
07a62b8
Delete rabi_length_signal.yaml
ElStabilini Nov 25, 2024
1873ccb
Update src/qibocal/protocols/rabi/utils.py
ElStabilini Nov 25, 2024
ef2e21a
Update src/qibocal/protocols/rabi/amplitude_frequency.py
ElStabilini Nov 25, 2024
7deade0
Update src/qibocal/protocols/rabi/length_frequency.py
ElStabilini Nov 25, 2024
222539d
Update src/qibocal/protocols/rabi/length_frequency.py
ElStabilini Nov 25, 2024
62230c9
Update src/qibocal/protocols/rabi/length.py
ElStabilini Nov 25, 2024
23ae111
Update src/qibocal/protocols/rabi/ef.py
ElStabilini Nov 25, 2024
4dbcc34
Update src/qibocal/protocols/rabi/length.py
ElStabilini Nov 25, 2024
3427756
Update update.py
ElStabilini Nov 25, 2024
3c676ff
Update protocols.yml
ElStabilini Nov 26, 2024
df453df
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 26, 2024
92e0d71
Update pyproject.toml
ElStabilini Nov 26, 2024
1f9d532
Update length_frequency.py
ElStabilini Nov 26, 2024
31db8b7
Update ef.py
ElStabilini Nov 26, 2024
c579cbb
Update flipping.py
ElStabilini Nov 26, 2024
64e5352
Update pyproject.toml
ElStabilini Nov 26, 2024
3c4e0d9
Update poetry.lock
ElStabilini Nov 27, 2024
04cf0f9
Update flipping.py
ElStabilini Nov 27, 2024
cf73084
modify amplitude_sequence and length_sequence for rx90, add flipping …
ElStabilini Nov 27, 2024
f6bfcaf
Update flipping.py
ElStabilini Nov 27, 2024
454f5b5
Update flipping.py
ElStabilini Nov 27, 2024
47a22b5
Update flipping.py
ElStabilini Nov 27, 2024
96dd44e
Update flipping.py
ElStabilini Nov 27, 2024
07a4bcd
Update flipping.py
ElStabilini Nov 27, 2024
e8cea9a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 27, 2024
4052755
Update flipping.py
ElStabilini Nov 27, 2024
12fedb5
fix FlippingResults and FlippingData class definition
ElStabilini Nov 28, 2024
b58e13a
fix globalbackends error: downgrade qibo
ElStabilini Nov 28, 2024
32308e2
Update flipping.rst
ElStabilini Nov 28, 2024
57904a1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 28, 2024
3b6769d
fix error in _fit method
ElStabilini Nov 28, 2024
29a1296
update documentation for flipping
ElStabilini Nov 28, 2024
022240d
fix tests for rx90
ElStabilini Nov 28, 2024
8b0995d
Update flipping.rst
ElStabilini Nov 28, 2024
98bcf1d
modify plot function in utils to have the correct name of the pulse c…
ElStabilini Nov 29, 2024
17ba606
'sync remote and local branch'
ElStabilini Nov 29, 2024
7b907ae
improve code for printing pulse names on reports
ElStabilini Nov 30, 2024
7660fde
fix compatibility with qibo v0.2.14
ElStabilini Dec 3, 2024
2d8c8f7
fix conflict with pyproject.toml for branch 0.2
ElStabilini Dec 3, 2024
1bac594
fix error in flipping sequence construction for rx90
ElStabilini Dec 3, 2024
af82fec
Merge branch '0.2' into pi_half
ElStabilini Dec 3, 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
20 changes: 17 additions & 3 deletions doc/source/protocols/flipping.rst
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
Flipping
========

The flipping experiment corrects the amplitude in the qubit drive pulse. In this experiment,
we applying an :math:`R_x(\pi/2)` rotation followed by :math:`N` flips (two :math:`R_x(\pi)` rotations)
The flipping experiment corrects the amplitude in the qubit drive pulse for :math:`R_x(\pi)` rotations. In this experiment,
we apply an :math:`R_x(\pi/2)` rotation followed by :math:`N` flips (two :math:`R_x(\pi)` rotations)
and we measure the qubit state.
The first :math:`R_x(\pi/2)` is necessary to discriminate the over rotations and under rotations of the :math:`R_x(\pi)` pulse:
without it the difference between the two cases is just a global phase, i.e., the
probabilities are the same. With the :math:`R_x(\pi/2)` pulse, in case of under rotations the state will be closer to :math:`\ket{0}`
after the initial flip, in the over rotations one the final state will be closer to :math:`\ket{1}`.

By fitting the resulting data with a sinusoidal function, we can determine the delta amplitude, which allows us to refine the
:math:`\pi` pulse amplitue.
:math:`\pi` pulse amplitude.

We implemented also a version of the flipping protocol to calibrate the drive pulse amplitude of the :math:`R_x(\pi/2)` rotations, in this case each :math:`R_x(\pi)` rotation is replaced by two math:`R_x(\pi/2)` rotations.

Parameters
^^^^^^^^^^
Expand All @@ -35,6 +37,18 @@ The expected output is the following:

.. image:: flipping.png

If the same experiment is run setting the `rx90: True` the flipping is performed to calibrate the amplitude of the :math:`R_x(\pi/2)` rotation

.. code-block:: yaml

- id: flipping
operation: flipping
parameters:
delta_amplitude: 0.05
nflips_max: 30
nflips_step: 1
rx90: True
Comment on lines +44 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to indent with spaces, not tabs (you can set your editor to do that)


Requirements
^^^^^^^^^^^^

Expand Down
26 changes: 26 additions & 0 deletions doc/source/protocols/rabi/rabi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Rabi rate is larger than the decay and the pure dephasing rate,

where :math:`\Omega_R` is the Rabi frequency and :math:`\tau` the decay time.

In qibocal we implemented also another version of the Rabi experiment which can be used to tune the amplitude (duration) of the drive pulse in order
to excite the qubit from the ground state up to state :math:`\frac{\ket{0}-i\ket{1}}{\sqrt{2}}`.

Parameters
^^^^^^^^^^

Expand Down Expand Up @@ -103,6 +106,29 @@ It follows an example runcard and plot for the signal exepriment

.. image:: rabi_signal.png

In all the previous examples we run Rabi experiments for calibrating the amplitude (duration) of the drive pulse
to excite the qubit from the ground state up to state :math:`\ket{1}`.
All these example runcards can be modified to calibrate the amplitude (duration) of the drive pulse
to excite the qubit from the ground state up to state :math:`\frac{\ket{0}-i\ket{1}}{\sqrt{2}}` by simply setting the `rx90` parameter to `True`.
Comment on lines +109 to +112
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of mentioning the experiment in the general section, and describe it only in the example, you may move this description up, and just cite here you're performing the pi/2 described above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moreover, a description of the sequence (i.e. "same, but replace each pi with two pi/2") and a brief motivation may be appreciated. Then, you may cite this section in the flipping, instead of repeating it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even a reference to the literature you consulted may be appreciated as well :)


In the following we show an example runcard

.. code-block:: yaml


- id: Rabi signal
operation: rabi_amplitude_signal
parameters:
min_amp: 0.01
max_amp: 0.16
step_amp: 0.002
pulse_length: 40
nshots: 1024
relaxation_time: 50000
rx90: True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another tab here ^^


.. image:: rabi_amplitude_rx90

Requirements
^^^^^^^^^^^^
- :ref:`qubit-spectroscopy`
Expand Down
Binary file added doc/source/protocols/rabi/rabi_amplitude_rx90.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
703 changes: 371 additions & 332 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ classifiers = [

[tool.poetry.dependencies]
python = ">=3.9,<3.12"
qibolab = { git = "https://github.com/qiboteam/qibolab.git" }
qibo = "^0.2.12"
qibolab = { git = "https://github.com/qiboteam/qibolab.git", branch = "pi_half" }
qibo = "0.2.12"
numpy = "^1.26.4"
scipy = "^1.10.1"
pandas = { version = "^2.2.2", extras = ["html"] }
Expand Down
81 changes: 57 additions & 24 deletions src/qibocal/protocols/flipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,45 @@


def flipping_sequence(
platform: CalibrationPlatform, qubit: QubitId, delta_amplitude: float, flips: int
platform: CalibrationPlatform,
qubit: QubitId,
delta_amplitude: float,
flips: int,
rx90: bool,
):
"""Pulse sequence for flipping experiment."""

sequence = PulseSequence()
natives = platform.natives.single_qubit[qubit]
sequence |= natives.R(theta=np.pi / 2)

for _ in range(flips):
if rx90:
sequence |= natives.RX90()

qd_channel, rx_pulse = natives.RX()[0]
for _ in range(flips):
qd_channel, qd_pulse = natives.RX90()[0]

rx_detuned = update.replace(
rx_pulse, amplitude=rx_pulse.amplitude + delta_amplitude
)
sequence.append((qd_channel, rx_detuned))
sequence.append((qd_channel, rx_detuned))
qd_detuned = update.replace(
qd_pulse, delta_amplitude=qd_pulse.amplitude + delta_amplitude
)

sequence |= natives.MZ()
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))

else:
sequence |= natives.R(theta=np.pi / 2)

for _ in range(flips):
qd_channel, qd_pulse = natives.RX()[0]

qd_detuned = update.replace(
qd_pulse, amplitude=qd_pulse.amplitude + delta_amplitude
)
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))

sequence |= natives.MZ()

return sequence

Expand All @@ -59,6 +79,8 @@ class FlippingParameters(Parameters):
Defaults to ``False``."""
delta_amplitude: float = 0
"""Amplitude detuning."""
rx90: bool = False
"""Calibration of native pi pulse, if true calibrates pi/2 pulse"""


@dataclass
Expand All @@ -73,6 +95,8 @@ class FlippingResults(Results):
"""Difference in amplitude between detuned value and fit."""
fitted_parameters: dict[QubitId, dict[str, float]]
"""Raw fitting output."""
rx90: bool
"""Pi or Pi_half calibration"""
chi2: dict[QubitId, list[float]] = field(default_factory=dict)
"""Chi squared estimate mean value and error. """

Expand All @@ -90,8 +114,10 @@ class FlippingData(Data):
"""Resonator type."""
delta_amplitude: float
"""Amplitude detuning."""
pi_pulse_amplitudes: dict[QubitId, float]
"""Pi pulse amplitudes for each qubit."""
pulse_amplitudes: dict[QubitId, float]
"""Pulse amplitudes for each qubit."""
rx90: bool
"""Pi or Pi_half calibration"""
data: dict[QubitId, npt.NDArray[FlippingType]] = field(default_factory=dict)
"""Raw data acquired."""

Expand Down Expand Up @@ -120,10 +146,15 @@ def _acquisition(
data = FlippingData(
resonator_type=platform.resonator_type,
delta_amplitude=params.delta_amplitude,
pi_pulse_amplitudes={
qubit: platform.natives.single_qubit[qubit].RX[0][1].amplitude
pulse_amplitudes={
qubit: (
platform.natives.single_qubit[qubit].RX90[0][1].amplitude
if params.rx90
else platform.natives.single_qubit[qubit].RX[0][1].amplitude
)
Comment on lines +152 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this is just for fun, and at the level of code golf. But just for you to know that such an option exists

Suggested change
qubit: (
platform.natives.single_qubit[qubit].RX90[0][1].amplitude
if params.rx90
else platform.natives.single_qubit[qubit].RX[0][1].amplitude
)
qubit: getattr(platform.natives.single_qubit[qubit], "RX90" if params.rx90 else "RX")[0][1].amplitude

for qubit in targets
},
rx90=params.rx90,
)

options = {
Expand All @@ -144,6 +175,7 @@ def _acquisition(
qubit=qubit,
delta_amplitude=params.delta_amplitude,
flips=flips,
rx90=params.rx90,
)

sequences.append(sequence)
Expand Down Expand Up @@ -197,9 +229,7 @@ def _fit(data: FlippingData) -> FlippingResults:
chi2 = {}
for qubit in qubits:
qubit_data = data[qubit]
detuned_pi_pulse_amplitude = (
data.pi_pulse_amplitudes[qubit] + data.delta_amplitude
)
detuned_pulse_amplitude = data.pulse_amplitudes[qubit] + data.delta_amplitude
y = qubit_data.prob
x = qubit_data.flips

Expand All @@ -222,10 +252,14 @@ def _fit(data: FlippingData) -> FlippingResults:
perr = np.sqrt(np.diag(perr)).tolist()
popt = popt.tolist()
correction = popt[2] / 2

if data.rx90:
correction = correction / 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some other contexts, there is a difference between redefinition and in-place mutation, and the distinction may be very relevant.

However, in this case it's just about a single scalar, so it makes no difference (to the point that a compiler may optimize the operation anyhow). So, better to use the idiomatic shortcut ;)

Suggested change
correction = correction / 2
correction /= 2


corrected_amplitudes[qubit] = [
float(detuned_pi_pulse_amplitude * np.pi / (np.pi + correction)),
float(detuned_pulse_amplitude * np.pi / (np.pi + correction)),
float(
detuned_pi_pulse_amplitude
detuned_pulse_amplitude
* np.pi
* 1
/ (np.pi + correction) ** 2
Expand All @@ -237,11 +271,9 @@ def _fit(data: FlippingData) -> FlippingResults:
fitted_parameters[qubit] = popt

delta_amplitude_detuned[qubit] = [
-correction * detuned_pi_pulse_amplitude / (np.pi + correction),
-correction * detuned_pulse_amplitude / (np.pi + correction),
np.abs(
np.pi
* detuned_pi_pulse_amplitude
* np.power(np.pi + correction, -2)
np.pi * detuned_pulse_amplitude * np.power(np.pi + correction, -2)
)
* perr[2]
/ 2,
Expand All @@ -267,6 +299,7 @@ def _fit(data: FlippingData) -> FlippingResults:
delta_amplitude,
delta_amplitude_detuned,
fitted_parameters,
data.rx90,
chi2,
)

Expand Down Expand Up @@ -358,7 +391,7 @@ def _plot(data: FlippingData, target: QubitId, fit: FlippingResults = None):


def _update(results: FlippingResults, platform: CalibrationPlatform, qubit: QubitId):
update.drive_amplitude(results.amplitude[qubit], platform, qubit)
update.drive_amplitude(results.amplitude[qubit], results.rx90, platform, qubit)


flipping = Routine(_acquisition, _fit, _plot, _update)
Expand Down
16 changes: 10 additions & 6 deletions src/qibocal/protocols/rabi/amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class RabiAmplitudeResults(RabiAmplitudeSignalResults):
class RabiAmplitudeData(Data):
"""RabiAmplitude data acquisition."""

rx90: bool
"""Pi or Pi_half calibration"""
durations: dict[QubitId, float] = field(default_factory=dict)
"""Pulse durations provided by the user."""
data: dict[QubitId, npt.NDArray[RabiAmpType]] = field(default_factory=dict)
Expand All @@ -55,7 +57,7 @@ def _acquisition(
"""

sequence, qd_pulses, ro_pulses, durations = utils.sequence_amplitude(
targets, params, platform
targets, params, platform, params.rx90
)

sweeper = Sweeper(
Expand All @@ -64,7 +66,7 @@ def _acquisition(
pulses=[qd_pulses[qubit] for qubit in targets],
)

data = RabiAmplitudeData(durations=durations)
data = RabiAmplitudeData(durations=durations, rx90=params.rx90)

# sweep the parameter
results = platform.execute(
Expand Down Expand Up @@ -128,19 +130,21 @@ def _fit(data: RabiAmplitudeData) -> RabiAmplitudeResults:

except Exception as e:
log.warning(f"Rabi fit failed for qubit {qubit} due to {e}.")
return RabiAmplitudeResults(pi_pulse_amplitudes, durations, fitted_parameters, chi2)
return RabiAmplitudeResults(
pi_pulse_amplitudes, durations, fitted_parameters, data.rx90, chi2
)


def _plot(data: RabiAmplitudeData, target: QubitId, fit: RabiAmplitudeResults = None):
"""Plotting function for RabiAmplitude."""
return utils.plot_probabilities(data, target, fit)
return utils.plot_probabilities(data, target, fit, data.rx90)


def _update(
results: RabiAmplitudeResults, platform: CalibrationPlatform, target: QubitId
):
update.drive_amplitude(results.amplitude[target], platform, target)
update.drive_duration(results.length[target], platform, target)
update.drive_amplitude(results.amplitude[target], results.rx90, platform, target)
update.drive_duration(results.length[target], results.rx90, platform, target)


rabi_amplitude = Routine(_acquisition, _fit, _plot, _update)
Expand Down
13 changes: 10 additions & 3 deletions src/qibocal/protocols/rabi/amplitude_frequency.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _acquisition(
"""Data acquisition for Rabi experiment sweeping amplitude."""

sequence, qd_pulses, ro_pulses, durations = sequence_amplitude(
targets, params, platform
targets, params, platform, params.rx90
)
frequency_range = np.arange(
params.min_freq,
Expand All @@ -101,7 +101,7 @@ def _acquisition(
pulses=[qd_pulses[qubit] for qubit in targets],
)

data = RabiAmplitudeFreqData(durations=durations)
data = RabiAmplitudeFreqData(durations=durations, rx90=params.rx90)

results = platform.execute(
[sequence],
Expand Down Expand Up @@ -186,6 +186,7 @@ def _fit(data: RabiAmplitudeFreqData) -> RabiAmplitudeFrequencyResults:
fitted_parameters=fitted_parameters,
frequency=fitted_frequencies,
chi2=chi2,
rx90=data.rx90,
)


Expand Down Expand Up @@ -234,10 +235,16 @@ def _plot(
row=1,
col=1,
)

if data.rx90:
pulse_name = "Pi-half pulse"
else:
pulse_name = "Pi pulse"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these cases, it is especially convenient to use the ternary if operator (exact same of the ... ? ... : ... construct in C)

Suggested change
if data.rx90:
pulse_name = "Pi-half pulse"
else:
pulse_name = "Pi pulse"
pulse_name = "Pi-half pulse" if data.rx90 else "Pi pulse"


fitting_report = table_html(
table_dict(
target,
["Optimal rabi frequency", "Pi-pulse amplitude"],
["Optimal rabi frequency", f"{pulse_name} amplitude"],
[
fit.frequency[target],
f"{fit.amplitude[target][0]:.6f} +- {fit.amplitude[target][1]:.6f} [a.u.]",
Expand Down
Loading