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

Make Sweeper pydantic Model and introduce range #1014

Merged
merged 15 commits into from
Aug 30, 2024
Merged

Conversation

stavros11
Copy link
Member

As discussed in #540 this drops the SweeperType from the interface.

QM is not updated, but since it never supported SweeperType before, it will still be working same as before. Following the discussion in #540, I need to change all sweepers to behave as ABSOLUTE. I will do this in another PR.

@stavros11 stavros11 requested a review from alecandido August 28, 2024 14:40
Copy link

codecov bot commented Aug 28, 2024

Codecov Report

Attention: Patch coverage is 88.09524% with 5 lines in your changes missing coverage. Please review.

Project coverage is 51.86%. Comparing base (8887534) to head (adbcb38).
Report is 16 commits behind head on 0.2.

Files with missing lines Patch % Lines
src/qibolab/instruments/zhinst/sweep.py 0.00% 2 Missing ⚠️
src/qibolab/instruments/qm/program/instructions.py 0.00% 1 Missing ⚠️
src/qibolab/instruments/qm/program/sweepers.py 0.00% 1 Missing ⚠️
src/qibolab/instruments/zhinst/executor.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              0.2    #1014      +/-   ##
==========================================
+ Coverage   51.77%   51.86%   +0.08%     
==========================================
  Files          58       58              
  Lines        2760     2765       +5     
==========================================
+ Hits         1429     1434       +5     
  Misses       1331     1331              
Flag Coverage Δ
unittests 51.86% <88.09%> (+0.08%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@stavros11 stavros11 added this to the Qibolab 0.2.0 milestone Aug 28, 2024
extras/test819.py Outdated Show resolved Hide resolved
Base automatically changed from rm-drivers to 0.2 August 28, 2024 15:29
@stavros11
Copy link
Member Author

@alecandido I changed Sweeper to pydantic Model in 5205f97. This had the side-effect of breaking various things including tests, because it doesn't support positional arguments anymore.

Currently from tests only test_dummy is broken. I can have a look and fix them, but I am not sure if it's worth it given #996. Maybe something in the docs is also broken, so I will convert to draft until I check and also confirm it didn't break QM.

@stavros11 stavros11 marked this pull request as draft August 28, 2024 15:53
@alecandido
Copy link
Member

@alecandido I changed Sweeper to pydantic Model in 5205f97. This had the side-effect of breaking various things including tests, because it doesn't support positional arguments anymore.

The example in the issue was Pydantic-based. But only because I'm personally leaning towards it, it's perfectly fine to use dataclasses in many cases.

The two motivations I see for using Pydantic are:

  1. better (de)serialization support - the reason why I introduced it
  2. more subclassing-friendly, that is the reason why I extended to Instrument (since there were many subclasses everywhere)

None of the two strict applies to the Sweeper. However, it is not a bad idea, simply not necessary. I expect a minor amount of fixes required anyhow.

Currently from tests only test_dummy is broken. I can have a look and fix them, but I am not sure if it's worth it given #996. Maybe something in the docs is also broken, so I will convert to draft until I check and also confirm it didn't break QM.

Regarding test_dummy we could even merge #996 immediately, it is ready. I was only waiting to drop some more tests, but I can convert the comment #996 (comment) to an issue with the missing points, and apply those in a separate PR.

About the docs, I'd suggest you taking a look at:

# TODO: the following is a workaround for Sphinx doctest, cf.
# - https://github.com/qiboteam/qibolab/commit/e04a6ab
# - https://github.com/pydantic/pydantic/discussions/7763
import qibolab.instruments.zhinst

Pydantic is a perfectly valid Python compiled extension, but Sphinx is going deeper below the surface than what Python strictly guarantees, apparently (indeed, in the past, I remember to have whitelisted even NumPy or other compiled extensions - maybe there were better solutions, but it was relevant that the issue was raised).
Pydantic has the added "benefit" that the BaseModel is made for subclassing. Importing the offending modules in conf.py seems to solve the issue (for unknown reasons related to the inner machinery of Sphinx)

channels: Optional[list] = None
type: Optional[SweeperType] = SweeperType.ABSOLUTE
values: Optional[npt.NDArray] = None
linspace: Optional[tuple[float, float, float]] = None
Copy link
Member

@alecandido alecandido Aug 28, 2024

Choose a reason for hiding this comment

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

Suggested change
linspace: Optional[tuple[float, float, float]] = None
range: Optional[tuple[float, float, float]] = None

?

@andrea-pasquale, @Edoardo-Pedicillo: any advice for a better name than those two?

Copy link
Contributor

Choose a reason for hiding this comment

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

What are values and linspace in this case?

Copy link
Member Author

Choose a reason for hiding this comment

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

Two different ways to define the sweeper values. values is an array containing all the points, same as in 0.1. range will be a tuple with three elements (start, stop, step) and the values will be defined as np.arange(start, stop, step). Only one of them should be given when initializing the Sweeper. If both are given it will raise an error.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed in 2726f27.

I forgot to say above that the idea is that range should be used whenever possible, as it is expected to be more efficient for most instruments. It should also be sufficient for most qibocal routines. values is still there for special cases where non-equidistant points need to be swept for some reason.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for clarifying, I would say that range is fine.

@stavros11 stavros11 mentioned this pull request Aug 28, 2024
2 tasks
@stavros11 stavros11 changed the base branch from 0.2 to clean-dummy-tests August 28, 2024 21:29
@stavros11 stavros11 changed the title Remove SweeperType Make Sweeper pydantic Model and introduce range Aug 28, 2024
Base automatically changed from clean-dummy-tests to 0.2 August 28, 2024 22:07
@stavros11
Copy link
Member Author

This should now also be ready. @alecandido what do you think about populating the actual values from range (when given) in some kind of __post_init__ (I am not sure if it is possible), instead of having the values_array property? The main reason is that I don't like much values_array, neither vals from the original proposal since it's not an actual word. I would like to use values both for initializing the Sweeper but also to return the values if the Sweeper was defined using range.

Note that drivers can still check if a Sweeper is range as they can check if sweeper.range is not None before accessing values.

@alecandido
Copy link
Member

This should now also be ready. @alecandido what do you think about populating the actual values from range (when given) in some kind of __post_init__ (I am not sure if it is possible)

Possible, it's called model_post_init. Instead of dunders (i.e. __xxx__) Pydantic is using a model_* scope.
https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_post_init

With Sweeper now being frozen, it can make even more sense: it's true that you're doing some (tiny) potentially unneeded computation ahead of time (with the property, you would compute the array from .range only if needed). But this is negligible.
Instead, the non-negligible risk was getting out-of-sync after instantiation, which is not possible (in a simple way), because it's frozen.

The main reason is that I don't like much values_array, neither vals from the original proposal since it's not an actual word. I would like to use values both for initializing the Sweeper but also to return the values if the Sweeper was defined using range.

We could find a better word. But there is some value in keeping a single way to access, because it would be less confusing.
In order to make proper use of the property, the attribute should have been private. Which it can't be, if we want it to be also a "field".

Note that drivers can still check if a Sweeper is range as they can check if sweeper.range is not None before accessing values.

This should not even happen: if a driver is capable of using (properly) the array, it should directly aim for that. And it will always be available.
If it isn't, it should just consume .range, and fail if not present (since the arbitrary array will be unsupported).

if self.range is None and self.values is None:
raise ValueError("Either 'range' or 'values' needs to be provided.")

return self
Copy link
Member

Choose a reason for hiding this comment

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

The model_post_init is only one option, and it's the one to be used when:

This is useful if you want to do some validation that requires the entire model to be initialized.
https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_post_init

And most likely this is our case.

However, even "after" validators can do a very similar job, and, e.g., you can assign Sweeper.values here (if None), right after having checked that the two of them are not provided simultaneously.

@stavros11
Copy link
Member Author

Thanks @alecandido. I made the change and dropped the values_array property in c5929b4.

@stavros11 stavros11 marked this pull request as ready for review August 28, 2024 23:04
@stavros11
Copy link
Member Author

Actually, it seems that I cannot change self.values because the object is frozen. I am checking how to fix.

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 made some changes myself, to slightly simplify qibolab.sweeper. Please, check them before merging.

Other than that, this is good to go.

@stavros11
Copy link
Member Author

Thanks @alecandido, looks good to me. I will merge when the CI passes.

@stavros11 stavros11 merged commit cd6dcd6 into 0.2 Aug 30, 2024
28 checks passed
@stavros11 stavros11 deleted the rm-sweeper-type branch August 30, 2024 12:36
@alecandido alecandido linked an issue Aug 30, 2024 that may be closed by this pull request
@stavros11 stavros11 mentioned this pull request Aug 30, 2024
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.

Drop SweeperType
3 participants