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

Merged
merged 81 commits into from
Dec 12, 2024
Merged

RX90 calibration implementation #1044

merged 81 commits into from
Dec 12, 2024

Conversation

ElStabilini
Copy link
Contributor

@ElStabilini ElStabilini commented Nov 20, 2024

Checklist:

  • Reviewers confirm new code works as expected.
  • Tests are passing.
  • Coverage does not decrease.
  • Documentation is updated.
  • Compatibility with Qibo modules (Please edit this section if the current pull request is not compatible with the following branches).
    • Qibo: master
    • Qibolab: main
    • Qibolab_platforms_qrc: main

@andrea-pasquale andrea-pasquale changed the base branch from main to 0.2 November 20, 2024 13:08
Copy link

codecov bot commented Nov 20, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.98%. Comparing base (4a1251a) to head (837cc08).
Report is 83 commits behind head on 0.2.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##              0.2    #1044      +/-   ##
==========================================
- Coverage   97.04%   96.98%   -0.07%     
==========================================
  Files          98       98              
  Lines        7893     7949      +56     
==========================================
+ Hits         7660     7709      +49     
- Misses        233      240       +7     
Flag Coverage Δ
unittests 96.98% <100.00%> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/qibocal/protocols/flipping.py 98.60% <100.00%> (+0.13%) ⬆️
src/qibocal/protocols/rabi/amplitude.py 96.87% <100.00%> (+0.10%) ⬆️
src/qibocal/protocols/rabi/amplitude_frequency.py 97.95% <100.00%> (+0.02%) ⬆️
...bocal/protocols/rabi/amplitude_frequency_signal.py 98.46% <100.00%> (+0.08%) ⬆️
src/qibocal/protocols/rabi/amplitude_signal.py 97.59% <100.00%> (+0.18%) ⬆️
src/qibocal/protocols/rabi/ef.py 100.00% <100.00%> (ø)
src/qibocal/protocols/rabi/length.py 96.20% <100.00%> (+0.09%) ⬆️
src/qibocal/protocols/rabi/length_frequency.py 97.05% <100.00%> (+0.02%) ⬆️
.../qibocal/protocols/rabi/length_frequency_signal.py 97.79% <100.00%> (+0.11%) ⬆️
src/qibocal/protocols/rabi/length_signal.py 96.59% <100.00%> (+0.24%) ⬆️
... and 2 more

... and 3 files with indirect coverage changes

@ElStabilini
Copy link
Contributor Author

I attach here some reports where I tested the code:

@andrea-pasquale
Copy link
Contributor

Thanks @ElStabilini, the results seem to make sense since for both amplitude and duration there is a factor 2. I think that rather than changing the protocol completly we could consider adding a flag to specify whether we want to calibrate the RX or RX90 pulse. We should also check the corresponding update function in the protocols to be consistent.
Eventually we can do the same for both the flipping and the drag calibration. For now let's finish first rabi.

src/qibocal/update.py Outdated Show resolved Hide resolved
src/qibocal/protocols/rabi/length_signal.py Outdated Show resolved Hide resolved
src/qibocal/protocols/rabi/length_frequency_signal.py Outdated Show resolved Hide resolved
@ElStabilini
Copy link
Contributor Author

ElStabilini commented Nov 21, 2024

Thanks @ElStabilini, the results seem to make sense since for both amplitude and duration there is a factor 2. I think that rather than changing the protocol completly we could consider adding a flag to specify whether we want to calibrate the RX or RX90 pulse. We should also check the corresponding update function in the protocols to be consistent. Eventually we can do the same for both the flipping and the drag calibration. For now let's finish first rabi.

@andrea-pasquale I see this only now, I should have done this by adding the pihalf_pulse (soon rx90) option, correct?
Regarding routines, should I change them even though I added a new RX90 native gate and left untouched the RX?

Copy link
Contributor

@andrea-pasquale andrea-pasquale left a comment

Choose a reason for hiding this comment

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

Thanks for the updates @ElStabilini.
At this point I would rename everywhere pihalf_pulse to rx90.
Everything else looks good to me.

doc/source/protocols/rabi/rabi.rst Outdated Show resolved Hide resolved
src/qibocal/protocols/rabi/ef.py Outdated Show resolved Hide resolved
doc/source/protocols/rabi/rabi.rst Outdated Show resolved Hide resolved
@andrea-pasquale andrea-pasquale changed the title RX$\pi/2$ calibration implementation RX90 calibration implementation Nov 21, 2024
Merge branch 'pi_half' of github.com:qiboteam/qibocal into pi_half
@andrea-pasquale
Copy link
Contributor

Regarding routines, should I change them even though I added a new RX90 native gate and left untouched the RX?

Just to avoid too many things at the same time I suggest to focus first on rabi experiments. In another PR we can propagate these changes to the other protocols.

@alecandido
Copy link
Member

@ElStabilini just to provide you some context about #1044 (comment), the clear advantage of the proposed syntax is neither saving characters nor lines.

The most prominent difference between the equivalent expressions is that one is imperative, the other functional.
In the first one, you or conditioning the entire assignment operation, as the process of defining a variable name and its associated value. In principle, you need to analyze both branches of the conditional to ensure that the variable (pulse_name in this case) is even defined.
Instead, when using the ternary operation you are not conditioning the assignment as an operation, which becomes just an alias for a given computation. The computation is an expression, that always has a value. But it's the value itself the one being conditioned.

The functional approach makes the computation flow clearer, since it is somehow more rigid (you're not even thinking about operations, and possibly memory, but just values manipulation), and makes the analysis simpler and more effective. In languages which are actually functional, this may empower the compiler to act more aggressively. In Python, it makes the linters more effective[*], leading to fewer errors and more helpful messages :)

[*]: since it optimizes the simplicity of the code, it makes it also more human-readable in general

@ElStabilini
Copy link
Contributor Author

@ElStabilini just to provide you some context about #1044 (comment), the clear advantage of the proposed syntax is neither saving characters nor lines.

The most prominent difference between the equivalent expressions is that one is imperative, the other functional. In the first one, you or conditioning the entire assignment operation, as the process of defining a variable name and its associated value. In principle, you need to analyze both branches of the conditional to ensure that the variable (pulse_name in this case) is even defined. Instead, when using the ternary operation you are not conditioning the assignment as an operation, which becomes just an alias for a given computation. The computation is an expression, that always has a value. But it's the value itself the one being conditioned.

The functional approach makes the computation flow clearer, since it is somehow more rigid (you're not even thinking about operations, and possibly memory, but just values manipulation), and makes the analysis simpler and more effective. In languages which are actually functional, this may empower the compiler to act more aggressively. In Python, it makes the linters more effective[*], leading to fewer errors and more helpful messages :)

[*]: since it optimizes the simplicity of the code, it makes it also more human-readable in general

It definitely makes sense, thank you!

@ElStabilini ElStabilini marked this pull request as ready for review December 3, 2024 15:31
Copy link
Member

@alecandido alecandido left a comment

Choose a reason for hiding this comment

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

Generally good, and pretty much ready to go.

The main suggestions are about the docs. The other ones are very minor refactor requests, which could even be neglected.

Comment on lines 44 to 50
- id: flipping
operation: flipping
parameters:
delta_amplitude: 0.05
nflips_max: 30
nflips_step: 1
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.

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

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 ^^

Copy link
Member

Choose a reason for hiding this comment

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

Still present...

Comment on lines +109 to +112
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`.
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 :)

Comment on lines 37 to 66
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.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))
sequence.append((qd_channel, qd_detuned))

sequence |= natives.MZ()

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

sequence |= natives.MZ()
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()
Copy link
Member

Choose a reason for hiding this comment

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

A good chunk of code is duplicated between the two branches. You may try to scope further the if within the sequence definition, to minimize duplication.

(In general, there is no exact solution about how to make code "minimal" or "simplest" - but here there is some room for improvements ^^)

src/qibocal/protocols/flipping.py Outdated Show resolved Hide resolved
src/qibocal/protocols/flipping.py Outdated Show resolved Hide resolved
Comment on lines 246 to 249
if rx90:
qd_channel, qd_pulse = natives.RX90()[0]
else:
qd_channel, qd_pulse = natives.RX()[0]
Copy link
Member

Choose a reason for hiding this comment

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

In case you like code golf as well, you may try to deduplicate even this one (but it's absolutely not needed)

extract_rabi(RabiAmplitudeEFData)


def test_extract_rabi():
Copy link
Member

Choose a reason for hiding this comment

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

This is redefining the former, thus shadowing it.

You have to use two different names in order to be able to access both, and thus also to run both in Pytest.

While a redefinition is not an error, it is unlikely that you want to define a function that already exists. Consequently, your editor may have warned you about this (or better, Ruff should have done it).

Copy link
Member

@alecandido alecandido left a comment

Choose a reason for hiding this comment

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

I did not test the current status, but I trust you did.

Other than some formatting, and tiny (and irrelevant) potential deduplication, this PR should be ready to go :)

Comment on lines 46 to 51
- id: flipping
operation: flipping
parameters:
delta_amplitude: 0.05
nflips_max: 30
nflips_step: 1
Copy link
Member

Choose a reason for hiding this comment

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

Still plenty of tabs, instead of spaces...

image

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.

Still present...

Copy link
Contributor

@andrea-pasquale andrea-pasquale left a comment

Choose a reason for hiding this comment

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

Thanks @ElStabilini for all the updates. I just have a few comments.
I still need to run the code on hardware myself but everything looks good so far.

Comment on lines 46 to 51
- id: flipping
operation: flipping
parameters:
delta_amplitude: 0.05
nflips_max: 30
nflips_step: 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Tab to be fixed

Comment on lines 37 to 40
if rx90:
sequence |= natives.RX90()
else:
sequence |= natives.R(theta=np.pi / 2)
Copy link
Contributor

Choose a reason for hiding this comment

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

Here it is not clear to me why we need to differentiate these two lines. I think we can just add the second version, since the fit is not "considering" the first RX90 since we extract the amplitude from the number of flips (which doesn't include the first one).

src/qibocal/protocols/flipping.py Outdated Show resolved Hide resolved
@ElStabilini ElStabilini merged commit 7b23156 into 0.2 Dec 12, 2024
21 checks passed
@ElStabilini ElStabilini deleted the pi_half branch December 12, 2024 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants